Check out a free preview of the full Firebase Fundamentals course:
The "Document Triggers" Lesson is part of the full, Firebase Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:

David live codes an example of a Cloud Function triggered by a document event. Users changing their data will trigger the Cloud Function to update it across all expenses.

Get Unlimited Access Now

Transcript from the "Document Triggers" Lesson

[00:00:00]
>> Another type of event that we'll look at is documents. So one of the things that we could do is we could say, hey, whenever a user writes out to a document, so documents of uid, and we provide a wildcard. Whenever these things are updated, we'll get the change back.

[00:00:25] And just like how I mentioned before, we could say hey, whenever someone mentions change, let's update all of their expenses with their new user profile. So I can use the Admin SDK for that, so const firestore is getFirestore. It has a very similar but not totally similar API because they're different feature sets than the Client SDK, but it's the same type of concepts.

[00:00:53] And I can say, all right, now that I have Firestore, right, not onCreate, right? And here I can say, all right let's get the user, or I should say, expensesQuery. And that's gonna be firestore.collection('expenses'). And if I happen to fan out, I could do, or if I had to use subcollection hierarchy, I could do it that way, but I can just say .where where('uid') is = = to.

[00:01:28] And within here actually, I can get the context and say context.Params, and one of the params will be uid. So now, I have the query. If I wanna get all the data, I can say snapshot and I'll write, expensesQuery.get. This will do a one-time get of all these expenses.

[00:02:03] And then now, I'll have the ability to say snapshot.forEach, and I can loop through and I'll say forEach(snapshot). This will give me every expense that belongs to that user. And before talked about using batches, so I could say const batch is firestore.batch. And now within each one I could say batch.update(snapshot).ref, because this is the reference of that expense, so where that expense lives in the database.

[00:02:45] And we wanna update it with a new piece of data, and we wanna update it with a new user. So to get the new user, that is the change that is happening. A user was updated, it's the change. And so changes are interesting because you can get the state before, and you can get the state after the change.

[00:03:04] And so that's really useful for any type of, hey, don't allow this to happen, or allow this to happen. There's so many good uses for this. I want to get the new change. So change, and I wanna get the after. And I believe, yeah, after is also a snapshot, so let's say user = after.data().

[00:03:31] So now, each one will get added to the batch. I need to, yeah, this should work. Feel like might be doing something wrong but we'll figure that out, we're doing everything locally. And now I can say await batch.commit(). And something to point out here is that this will atomically update all of this data.

[00:03:57] But if there are more than 500, it will throw an error. I know that there's, not in this case. So there's a couple of things that I could do. Maybe it's not important that it all happens atomically, so I could just read through it. Also we learned how to do cursors, so we could curse through it and say, hey, let's create batches and cursors, so it happens over time.

[00:04:16] But in general, if you are doing more than 500 or really more than I'd say like 1,000 or so, this kind of thing should be more of a cron job style thing, or done on something that's meant to be a much more longer process. Cloud functions are only supposed to be running for certain set of time.

[00:04:32] I can't remember what their max timeout is, but in general it's not supposed to be a very long server process. There are other tools for that, though. So now let's go through, emulators are running, that's great. And now I wanna go into the admin SDK, and what I wanna do is, as I zoom out here, Store, great, so let's say we go into the first user and, let's see here, and this user changes their city.

[00:05:07] So they no longer live in Maputo, they now live in, Washington DC. Now we save, and maybe some things are happening. Let's copy this uid, cuz it's important. And let's go into the logs. So the logs will show me if anything happened. It says beginning execution of update user expenses, Right in here, but we didn't see any errors, so let's see if it worked.

[00:05:46] It's now in Firestore, I can go into expenses and zoom out a little. And no no, don't delete, that would have been bad. Man, I accidentally copied that ID. All right, let's do it on another user cuz I'm gonna lose their ID. So user moved from Santiago to Washington DC.

[00:06:10] Let's get their ID, Check the logs again. All right, that looks good. Now let's go to expenses and let's run a filter. And so I can say where UID is equal to this string, apply. And so now if we go into user, look at that, they're now Washington DC.

[00:06:33] So that fanned out all of those updates. So if I expect that to be a rare operation where profiles don't change that much, or maybe I only wanna update on certain fields. So as you can see, we can check to see what field. Maybe I only wanna update if they change their industry, or if they change their names or whatever.

[00:06:52] So you can then fan out all of those updates. So that is a really good use case for being able to keep data denormalized across places, and just kind of happens automatically as events occur.