Retrieve data from Firestore in a way that is faster and more cost effective with data aggregation. In this episode, we use Firebase Cloud Functions to read data from a sub-collection and write it to its parent document. https://angularfirebase.com/lessons/firestore-cloud-functions-data-aggregation/

Firestore: https://firebase.google.com/docs/firestore/
NoSQL Aggregation: https://www.thoughtworks.com/insights/blog/nosql-databases-overview
2024-02-04T07:58:17.840Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
f23531c0-a3c3-4426-b96f-343ccbdb5d21
73b32fff6ec94ff6d0c4ea880701985adb02bd9b0d6ed07a61ad677aaea1d87e
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
Are you interested in retrieving data from the Firestore database in a way that's both faster and more cost effective?
If so, you're watching the right video.
Today, I'm going to show you how to use Firebase Cloud Functions to automatically aggregate or add up information from a sub collection and then write it to its parent document.
Take for example a post document that has a comment sub collection nested under it.
Whenever a new comment is created, it's going to trigger a cloud function that will read this comment sub collection, then add up the comment count and the 5 most recent comments, and then duplicate them on the post document.
On a NoSQL document database like Firestore, duplication is perfectly acceptable.
Imagine if we had a post with a 100 comments.
We'd have to read all those comments to get the total every time someone viewed a post.
Not only is that slower for the end user, but it's also gonna cost a lot more money as your app scales up.
My goal today is to show you how to solve this problem using back end data aggregation.
If you're new here, make sure to subscribe and you can grab the full source code from angularfirebasedot comm.
I'm going to be starting from a brand new Angular app, so run ng new.
Its only dependency is AngularFire 2, and you can follow the setup instructions for that on the main repo.
If you're not using Angular, you can skip ahead to the Cloud Function code, which is just written in plain JavaScript.
The first thing I'll show you is our underlying data.
We have a post collection and then this test post under it.
Then you can see we have a recent comments array here, which is the 5 most recent comments from potentially 100 or even 1000 of comments in the sub collection.
Having this data on the parent doc is extremely useful if you loop through a list of posts and you just wanna show quick preview of the most recent comment as well as the total comment count.
The comment sub collection is very simple.
It just has a content property and a created at timestamp.
At this point, I wanna point out that this is not suitable for every situation.
It's ideal when you have documents that receive many reads but not very many writes.
A good example would be Yelp, where many users want to see the reviews for a location, but only a small percentage actually write a review.
Getting back to Angular, you're going to need to run Firebase init functions if you're in a new project.
And then, we're not going to install anything special, we can just use the default packages.
But make sure they're updated to the newest version because Firestore is a relatively new product.
We'll write this Cloud Function in a few minutes.
Let's first make the query without any data aggregation.
I am switching over to the App component, and then I'm going to import Observable from RxJS as well as AngularFirestore.
Then I can go ahead and inject AngularFirestore in the constructor.
From there, I'll declare a variable for our post reference, which is an AngularFirestore document, and then we'll set another variable for the observable.
And we'll do the exact same thing here for the comments, but it'll be an AngularFirestore collection.
Then we'll add one more variable for form value which we'll get from the form input in the HTML.
During ng on init, we'll first make a reference to the document that we want, which in this case is just called testPost.
And then we can make a reference to its comment sub collection by calling Collection on that reference.
So we say post ref collection comments.
And it's also important that we order by something.
In this case, we have a timestamp on the comments.
So we'll say order by created at and make that descending.
Then to actually retrieve our post, we call post ref value changes and that returns it as an observable.
Then we can do the exact same thing for comments.
Then we're going to switch over to the HTML and we'll set a template variable for our post.
So we unwrap that with the async pipe and then say 'as post'.
And then from there we'll just display the post title and the post Content.
Then we'll go ahead and set up a form input here and bind it with 'ngmodel'.
Then when the user hits the enter key, we'll go ahead and and run a function to update that in the database.
Right now we have a comments observable, so we'll go ahead and loop over that with the async pipe.
But after we perform some data aggregation, we'll be able to read this information directly from the post document.
So at this point we have our Log Post here and then the user can enter their comment and it's updated in real time.
The problem here is we're reading multiple documents when we could only just read 1, and we also don't have an efficient way to keep track of a comment count or any other aggregate data.
So let's go ahead and solve this by writing a Cloud Function.
We're going to import the admin database and make sure that's initialized.
Then we're going to run the function whenever a new comment document is written to the database.
So we do that by saying functions Firestore document, then point it to the comment ID nested under the post.
Using on right will run this function whenever a document is created, updated, or deleted.
First, we'll set a couple variables here for the comment ID and the post ID.
So we do that by calling event params with the corresponding ID.
Then after we have those IDs, we'll set up a reference 2, the post document.
We're going to do that with the admin database, which will allow us to bypass any Firestore rules that we have set up.
Then from there, we need to query the collection of comments that are nested under this document so we can add them up and aggregate them.
In a Cloud Function, we're using the main Firebase SDK as opposed to AngularFire 2, so we do things slightly different.
Instead of calling value changes, we call get.
That returns a promise with the query snapshot.
The query snapshot contains all of the documents that we need, and it behaves kind of like an array, but you can't use the regular JavaScript prototype array methods on it.
To get the size of the collection, we can call query snapshot size.
And then to get all of the recent comments, we'll set up an array here.
Then we can loop over the snapshots with the for each method, and for each comment, we're going to push it to our array.
At this point, you have an array of data that you could perform any kind of data aggregation task that you want.
But for now, we're just going to splice the last five comments.
And we'll also set a property for the last activity, which would be the last time any user has placed a comment on this post.
And then finally, we add all of this data to an object, then we can call update on our document reference.
Then we'll also go ahead and console log errors here, but overall, it's a pretty simple cloud function.
I'd like to point out that if you're doing pull updates in this function.
You'd want to wrap it in either a transaction or do them all in a single batch.
That will ensure all your aggregate data stays in sync and is updated Tomically.
The final step is to deploy this function to Firebase, so we just run firebase deploy only functions.
Now let's modify our Angular app to take advantage of this function.
Back in the App component, first notice that I've removed the comments observable from ngOnInit.
Instead, we're going to lazy load it only when necessary.
Then users can actually still add a comment without even loading the comments collection.
Because we have the comments ref we can just call add and pass it some data.
We're going to show the user the first five comments, which will be on the document.
If the user wants to load more, we'll give them a button to click, which will lazily populate the comments observable.
In AngularFire 2, the while data isn't read until you call value changes.
Now we just need to make some changes to our App component HTML to show the aggregate data.
So first up here, we'll show the total comment count as well as the time stamp on the last activity.
Then we'll set up another for loop because now we have an array on the document itself, but we only wanna show this if the comments observable isn't populated.
So we can just do n g f no comments observable, then we'll go ahead and show the 5 most recent comments.
This data is already unwrapped by the post observable, so we can just call post recent comments and we don't need to use the async pipe.
And then we'll just go ahead and display the same exact data.
If the user decides they want to load all of the comments, then we'll give them a button down here to do so.
So we'll just say click and then run our load more event handler and we can show them how many comments are on this post.
In the app itself, take a look at the total comments which is currently 11.
Then if we go ahead and add another comment, you'll see it gets updated down there in the feed and the total comments is updated to 12 with about maybe a second or so of latency.
The latency is a little bit higher, but that is one of the trade offs when you're doing aggregation.
So here we're looking at the post document in Firestore and you can see it's updated each time we add a new comment.
If 99% of your users read the blog post but don't leave a comment, This is going to vastly reduce the number of reads that you execute in Firestore.
Not only is that going to save you money as you gain more users, but it's also going to make your app much more performant.
That's it for data aggregation with Firestore.
If this video helped you, please like and subscribe.
And, if you want twice as much content every week, Consider becoming a pro subscriber at angularfirebase.com.
You'll get a free copy of my book as well as an extra video every week.
And I even provide 1 on 1 port via our Slack team.
Thanks for watching and I'll see you next time.

Speaker 0: Are you interested in retrieving data from the Firestore database in a way that's both faster and more cost effective? If so, you're watching the right video. Today, I'm going to show you how to use Firebase Cloud Functions to automatically aggregate or add up information from a sub collection and then write it to its parent document. Take for example a post document that has a comment sub collection nested under it. Whenever a new comment is created, it's going to trigger a cloud function that will read this comment sub collection, then add up the comment count and the 5 most recent comments, and then duplicate them on the post document.

On a NoSQL document database like Firestore, duplication is perfectly acceptable. Imagine if we had a post with a 100 comments. We'd have to read all those comments to get the total every time someone viewed a post. Not only is that slower for the end user, but it's also gonna cost a lot more money as your app scales up. My goal today is to show you how to solve this problem using back end data aggregation.

If you're new here, make sure to subscribe and you can grab the full source code from angularfirebasedot comm. I'm going to be starting from a brand new Angular app, so run ng new. Its only dependency is AngularFire 2, and you can follow the setup instructions for that on the main repo. If you're not using Angular, you can skip ahead to the Cloud Function code, which is just written in plain JavaScript. The first thing I'll show you is our underlying data.

We have a post collection and then this test post under it. Then you can see we have a recent comments array here, which is the 5 most recent comments from potentially 100 or even 1000 of comments in the sub collection. Having this data on the parent doc is extremely useful if you loop through a list of posts and you just wanna show quick preview of the most recent comment as well as the total comment count. The comment sub collection is very simple. It just has a content property and a created at timestamp.

At this point, I wanna point out that this is not suitable for every situation. It's ideal when you have documents that receive many reads but not very many writes. A good example would be Yelp, where many users want to see the reviews for a location, but only a small percentage actually write a review. Getting back to Angular, you're going to need to run Firebase init functions if you're in a new project. And then, we're not going to install anything special, we can just use the default packages.

But make sure they're updated to the newest version because Firestore is a relatively new product. We'll write this Cloud Function in a few minutes. Let's first make the query without any data aggregation. I am switching over to the App component, and then I'm going to import Observable from RxJS as well as AngularFirestore. Then I can go ahead and inject AngularFirestore in the constructor.

From there, I'll declare a variable for our post reference, which is an AngularFirestore document, and then we'll set another variable for the observable. And we'll do the exact same thing here for the comments, but it'll be an AngularFirestore collection. Then we'll add one more variable for form value which we'll get from the form input in the HTML. During ng on init, we'll first make a reference to the document that we want, which in this case is just called testPost. And then we can make a reference to its comment sub collection by calling Collection on that reference.

So we say post ref collection comments. And it's also important that we order by something. In this case, we have a timestamp on the comments. So we'll say order by created at and make that descending. Then to actually retrieve our post, we call post ref value changes and that returns it as an observable.

Then we can do the exact same thing for comments. Then we're going to switch over to the HTML and we'll set a template variable for our post. So we unwrap that with the async pipe and then say 'as post'. And then from there we'll just display the post title and the post Content. Then we'll go ahead and set up a form input here and bind it with 'ngmodel'.

Then when the user hits the enter key, we'll go ahead and and run a function to update that in the database. Right now we have a comments observable, so we'll go ahead and loop over that with the async pipe. But after we perform some data aggregation, we'll be able to read this information directly from the post document. So at this point we have our Log Post here and then the user can enter their comment and it's updated in real time. The problem here is we're reading multiple documents when we could only just read 1, and we also don't have an efficient way to keep track of a comment count or any other aggregate data.

So let's go ahead and solve this by writing a Cloud Function. We're going to import the admin database and make sure that's initialized. Then we're going to run the function whenever a new comment document is written to the database. So we do that by saying functions Firestore document, then point it to the comment ID nested under the post. Using on right will run this function whenever a document is created, updated, or deleted.

First, we'll set a couple variables here for the comment ID and the post ID. So we do that by calling event params with the corresponding ID. Then after we have those IDs, we'll set up a reference 2, the post document. We're going to do that with the admin database, which will allow us to bypass any Firestore rules that we have set up. Then from there, we need to query the collection of comments that are nested under this document so we can add them up and aggregate them.

In a Cloud Function, we're using the main Firebase SDK as opposed to AngularFire 2, so we do things slightly different. Instead of calling value changes, we call get. That returns a promise with the query snapshot. The query snapshot contains all of the documents that we need, and it behaves kind of like an array, but you can't use the regular JavaScript prototype array methods on it. To get the size of the collection, we can call query snapshot size.

And then to get all of the recent comments, we'll set up an array here. Then we can loop over the snapshots with the for each method, and for each comment, we're going to push it to our array. At this point, you have an array of data that you could perform any kind of data aggregation task that you want. But for now, we're just going to splice the last five comments. And we'll also set a property for the last activity, which would be the last time any user has placed a comment on this post.

And then finally, we add all of this data to an object, then we can call update on our document reference. Then we'll also go ahead and console log errors here, but overall, it's a pretty simple cloud function. I'd like to point out that if you're doing pull updates in this function. You'd want to wrap it in either a transaction or do them all in a single batch. That will ensure all your aggregate data stays in sync and is updated Tomically.

The final step is to deploy this function to Firebase, so we just run firebase deploy only functions. Now let's modify our Angular app to take advantage of this function. Back in the App component, first notice that I've removed the comments observable from ngOnInit. Instead, we're going to lazy load it only when necessary. Then users can actually still add a comment without even loading the comments collection.

Because we have the comments ref we can just call add and pass it some data. We're going to show the user the first five comments, which will be on the document. If the user wants to load more, we'll give them a button to click, which will lazily populate the comments observable. In AngularFire 2, the while data isn't read until you call value changes. Now we just need to make some changes to our App component HTML to show the aggregate data.

So first up here, we'll show the total comment count as well as the time stamp on the last activity. Then we'll set up another for loop because now we have an array on the document itself, but we only wanna show this if the comments observable isn't populated. So we can just do n g f no comments observable, then we'll go ahead and show the 5 most recent comments. This data is already unwrapped by the post observable, so we can just call post recent comments and we don't need to use the async pipe. And then we'll just go ahead and display the same exact data.

If the user decides they want to load all of the comments, then we'll give them a button down here to do so. So we'll just say click and then run our load more event handler and we can show them how many comments are on this post. In the app itself, take a look at the total comments which is currently 11. Then if we go ahead and add another comment, you'll see it gets updated down there in the feed and the total comments is updated to 12 with about maybe a second or so of latency. The latency is a little bit higher, but that is one of the trade offs when you're doing aggregation.

So here we're looking at the post document in Firestore and you can see it's updated each time we add a new comment. If 99% of your users read the blog post but don't leave a comment, This is going to vastly reduce the number of reads that you execute in Firestore. Not only is that going to save you money as you gain more users, but it's also going to make your app much more performant. That's it for data aggregation with Firestore. If this video helped you, please like and subscribe.

And, if you want twice as much content every week, Consider becoming a pro subscriber at angularfirebase.com. You'll get a free copy of my book as well as an extra video every week. And I even provide 1 on 1 port via our Slack team. Thanks for watching and I'll see you next time.
Are you interested in retrieving data from the Firestore database in a way that's both faster and more cost effective? If so, you're watching the right video. Today, I'm going to show you how to use Firebase Cloud Functions to automatically aggregate or add up information from a sub collection and then write it to its parent document.
databases
streaming
Take for example a post document that has a comment sub collection nested under it. Whenever a new comment is created, it's going to trigger a cloud function that will read this comment sub collection, then add up the comment count and the 5 most recent comments, and then duplicate them on the post document.
blogging
On a NoSQL document database like Firestore, duplication is perfectly acceptable. Imagine if we had a post with a 100 comments. We'd have to read all those comments to get the total every time someone viewed a post. Not only is that slower for the end user, but it's also gonna cost a lot more money as your app scales up. My goal today is to show you how to solve this problem using back end data aggregation. If you're new here, make sure to subscribe and you can grab the full source code from angularfirebasedot comm. I'm going to be starting from a brand new Angular app, so run ng new. Its only dependency is AngularFire 2, and you can follow the setup instructions for that on the main repo. If you're not using Angular, you can skip ahead to the Cloud Function code, which is just written in plain JavaScript.
The first thing I'll show you is our underlying data. We have a post collection and then this test post under it. Then you can see we have a recent comments array here, which is the 5 most recent comments from potentially 100 or even 1000 of comments in the sub collection.
data analysis
data
Having this data on the parent doc is extremely useful if you loop through a list of posts and you just wanna show quick preview of the most recent comment as well as the total comment count. The comment sub collection is very simple. It just has a content property and a created at timestamp. At this point, I wanna point out that this is not suitable for every situation. It's ideal when you have documents that receive many reads but not very many writes. A good example would be Yelp, where many users want to see the reviews for a location, but only a small percentage actually write a review. Getting back to Angular, you're going to need to run Firebase init functions if you're in a new project. And then, we're not going to install anything special, we can just use the default packages. But make sure they're updated to the newest version because Firestore is a relatively new product. We'll write this Cloud Function in a few minutes. Let's first make the query without any data aggregation. I am switching over to the App component, and then I'm going to import Observable from RxJS as well as AngularFirestore. Then I can go ahead and inject AngularFirestore in the constructor. From there, I'll declare a variable for our post reference, which is an AngularFirestore document, and then we'll set another variable for the observable.
And we'll do the exact same thing here for the comments, but it'll be an AngularFirestore collection. Then we'll add one more variable for form value which we'll get from the form input in the HTML. During ng on init, we'll first make a reference to the document that we want, which in this case is just called testPost. And then we can make a reference to its comment sub collection by calling Collection on that reference. So we say post ref collection comments. And it's also important that we order by something.
documentation
In this case, we have a timestamp on the comments. So we'll say order by created at and make that descending. Then to actually retrieve our post, we call post ref value changes and that returns it as an observable. Then we can do the exact same thing for comments. Then we're going to switch over to the HTML and we'll set a template variable for our post. So we unwrap that with the async pipe and then say 'as post'. And then from there we'll just display the post title and the post Content. Then we'll go ahead and set up a form input here and bind it with 'ngmodel'. Then when the user hits the enter key, we'll go ahead and and run a function to update that in the database. Right now we have a comments observable, so we'll go ahead and loop over that with the async pipe. But after we perform some data aggregation, we'll be able to read this information directly from the post document.
So at this point we have our Log Post here and then the user can enter their comment and it's updated in real time. The problem here is we're reading multiple documents when we could only just read 1, and we also don't have an efficient way to keep track of a comment count or any other aggregate data. So let's go ahead and solve this by writing a Cloud Function. We're going to import the admin database and make sure that's initialized. Then we're going to run the function whenever a new comment document is written to the database. So we do that by saying functions Firestore document, then point it to the comment ID nested under the post.
databases
blogging
Using on right will run this function whenever a document is created, updated, or deleted. First, we'll set a couple variables here for the comment ID and the post ID. So we do that by calling event params with the corresponding ID.
Then after we have those IDs, we'll set up a reference 2, the post document. We're going to do that with the admin database, which will allow us to bypass any Firestore rules that we have set up. Then from there, we need to query the collection of comments that are nested under this document so we can add them up and aggregate them.
databases
In a Cloud Function, we're using the main Firebase SDK as opposed to AngularFire 2, so we do things slightly different. Instead of calling value changes, we call get. That returns a promise with the query snapshot. The query snapshot contains all of the documents that we need, and it behaves kind of like an array, but you can't use the regular JavaScript prototype array methods on it.
To get the size of the collection, we can call query snapshot size. And then to get all of the recent comments, we'll set up an array here. Then we can loop over the snapshots with the for each method, and for each comment, we're going to push it to our array.
databases
At this point, you have an array of data that you could perform any kind of data aggregation task that you want. But for now, we're just going to splice the last five comments. And we'll also set a property for the last activity, which would be the last time any user has placed a comment on this post. And then finally, we add all of this data to an object, then we can call update on our document reference. Then we'll also go ahead and console log errors here, but overall, it's a pretty simple cloud function. I'd like to point out that if you're doing pull updates in this function. You'd want to wrap it in either a transaction or do them all in a single batch. That will ensure all your aggregate data stays in sync and is updated Tomically. The final step is to deploy this function to Firebase, so we just run firebase deploy only functions. Now let's modify our Angular app to take advantage of this function. Back in the App component, first notice that I've removed the comments observable from ngOnInit. Instead, we're going to lazy load it only when necessary. Then users can actually still add a comment without even loading the comments collection. Because we have the comments ref we can just call add and pass it some data. We're going to show the user the first five comments, which will be on the document. If the user wants to load more, we'll give them a button to click, which will lazily populate the comments observable. In AngularFire 2, the while data isn't read until you call value changes. Now we just need to make some changes to our App component HTML to show the aggregate data. So first up here, we'll show the total comment count as well as the time stamp on the last activity. Then we'll set up another for loop because now we have an array on the document itself, but we only wanna show this if the comments observable isn't populated. So we can just do n g f no comments observable, then we'll go ahead and show the 5 most recent comments. This data is already unwrapped by the post observable, so we can just call post recent comments and we don't need to use the async pipe. And then we'll just go ahead and display the same exact data. If the user decides they want to load all of the comments, then we'll give them a button down here to do so. So we'll just say click and then run our load more event handler and we can show them how many comments are on this post. In the app itself, take a look at the total comments which is currently 11. Then if we go ahead and add another comment, you'll see it gets updated down there in the feed and the total comments is updated to 12 with about maybe a second or so of latency.
The latency is a little bit higher, but that is one of the trade offs when you're doing aggregation. So here we're looking at the post document in Firestore and you can see it's updated each time we add a new comment. If 99% of your users read the blog post but don't leave a comment, This is going to vastly reduce the number of reads that you execute in Firestore. Not only is that going to save you money as you gain more users, but it's also going to make your app much more performant. That's it for data aggregation with Firestore. If this video helped you, please like and subscribe. And, if you want twice as much content every week, Consider becoming a pro subscriber at angularfirebase.com. You'll get a free copy of my book as well as an extra video every week. And I even provide 1 on 1 port via our Slack team. Thanks for watching and I'll see you next time.
blogging
streaming
publishing
youtube
books
documentary
podcasts
websites
customer support
customers
Are you interested in retrieving data from the Firestore database in a way that's both faster and more cost effective? If so, you're watching the right video. Today, I'm going to show you how to use Firebase Cloud Functions to automatically aggregate or add up information from a sub collection and then write it to its parent document. Take for example a post document that has a comment sub collection nested under it. Whenever a new comment is created, it's going to trigger a cloud function that will read this comment sub collection, then add up the comment count and the 5 most recent comments, and then duplicate them on the post document. On a NoSQL document database like Firestore, duplication is perfectly acceptable. Imagine if we had a post with a 100 comments. We'd have to read all those comments to get the total every time someone viewed a post. Not only is that slower for the end user, but it's also gonna cost a lot more money as your app scales up. My goal today is to show you how to solve this problem using back end data aggregation. If you're new here, make sure to subscribe and you can grab the full source code from angularfirebasedot comm. I'm going to be starting from a brand new Angular app, so run ng new. Its only dependency is AngularFire 2, and you can follow the setup instructions for that on the main repo. If you're not using Angular, you can skip ahead to the Cloud Function code, which is just written in plain JavaScript. The first thing I'll show you is our underlying data. We have a post collection and then this test post under it. Then you can see we have a recent comments array here, which is the 5 most recent comments from potentially 100 or even 1000 of comments in the sub collection. Having this data on the parent doc is extremely useful if you loop through a list of posts and you just wanna show quick preview of the most recent comment as well as the total comment count. The comment sub collection is very simple. It just has a content property and a created at timestamp. At this point, I wanna point out that this is not suitable for every situation. It's ideal when you have documents that receive many reads but not very many writes. A good example would be Yelp, where many users want to see the reviews for a location, but only a small percentage actually write a review. Getting back to Angular, you're going to need to run Firebase init functions if you're in a new project. And then, we're not going to install anything special, we can just use the default packages. But make sure they're updated to the newest version because Firestore is a relatively new product. We'll write this Cloud Function in a few minutes. Let's first make the query without any data aggregation. I am switching over to the App component, and then I'm going to import Observable from RxJS as well as AngularFirestore. Then I can go ahead and inject AngularFirestore in the constructor. From there, I'll declare a variable for our post reference, which is an AngularFirestore document, and then we'll set another variable for the observable. And we'll do the exact same thing here for the comments, but it'll be an AngularFirestore collection. Then we'll add one more variable for form value which we'll get from the form input in the HTML. During ng on init, we'll first make a reference to the document that we want, which in this case is just called testPost. And then we can make a reference to its comment sub collection by calling Collection on that reference. So we say post ref collection comments. And it's also important that we order by something. In this case, we have a timestamp on the comments. So we'll say order by created at and make that descending. Then to actually retrieve our post, we call post ref value changes and that returns it as an observable. Then we can do the exact same thing for comments. Then we're going to switch over to the HTML and we'll set a template variable for our post. So we unwrap that with the async pipe and then say 'as post'. And then from there we'll just display the post title and the post Content. Then we'll go ahead and set up a form input here and bind it with 'ngmodel'. Then when the user hits the enter key, we'll go ahead and and run a function to update that in the database. Right now we have a comments observable, so we'll go ahead and loop over that with the async pipe. But after we perform some data aggregation, we'll be able to read this information directly from the post document. So at this point we have our Log Post here and then the user can enter their comment and it's updated in real time. The problem here is we're reading multiple documents when we could only just read 1, and we also don't have an efficient way to keep track of a comment count or any other aggregate data. So let's go ahead and solve this by writing a Cloud Function. We're going to import the admin database and make sure that's initialized. Then we're going to run the function whenever a new comment document is written to the database. So we do that by saying functions Firestore document, then point it to the comment ID nested under the post. Using on right will run this function whenever a document is created, updated, or deleted. First, we'll set a couple variables here for the comment ID and the post ID. So we do that by calling event params with the corresponding ID. Then after we have those IDs, we'll set up a reference 2, the post document. We're going to do that with the admin database, which will allow us to bypass any Firestore rules that we have set up. Then from there, we need to query the collection of comments that are nested under this document so we can add them up and aggregate them. In a Cloud Function, we're using the main Firebase SDK as opposed to AngularFire 2, so we do things slightly different. Instead of calling value changes, we call get. That returns a promise with the query snapshot. The query snapshot contains all of the documents that we need, and it behaves kind of like an array, but you can't use the regular JavaScript prototype array methods on it. To get the size of the collection, we can call query snapshot size. And then to get all of the recent comments, we'll set up an array here. Then we can loop over the snapshots with the for each method, and for each comment, we're going to push it to our array. At this point, you have an array of data that you could perform any kind of data aggregation task that you want. But for now, we're just going to splice the last five comments. And we'll also set a property for the last activity, which would be the last time any user has placed a comment on this post. And then finally, we add all of this data to an object, then we can call update on our document reference. Then we'll also go ahead and console log errors here, but overall, it's a pretty simple cloud function. I'd like to point out that if you're doing pull updates in this function. You'd want to wrap it in either a transaction or do them all in a single batch. That will ensure all your aggregate data stays in sync and is updated Tomically. The final step is to deploy this function to Firebase, so we just run firebase deploy only functions. Now let's modify our Angular app to take advantage of this function. Back in the App component, first notice that I've removed the comments observable from ngOnInit. Instead, we're going to lazy load it only when necessary. Then users can actually still add a comment without even loading the comments collection. Because we have the comments ref we can just call add and pass it some data. We're going to show the user the first five comments, which will be on the document. If the user wants to load more, we'll give them a button to click, which will lazily populate the comments observable. In AngularFire 2, the while data isn't read until you call value changes. Now we just need to make some changes to our App component HTML to show the aggregate data. So first up here, we'll show the total comment count as well as the time stamp on the last activity. Then we'll set up another for loop because now we have an array on the document itself, but we only wanna show this if the comments observable isn't populated. So we can just do n g f no comments observable, then we'll go ahead and show the 5 most recent comments. This data is already unwrapped by the post observable, so we can just call post recent comments and we don't need to use the async pipe. And then we'll just go ahead and display the same exact data. If the user decides they want to load all of the comments, then we'll give them a button down here to do so. So we'll just say click and then run our load more event handler and we can show them how many comments are on this post. In the app itself, take a look at the total comments which is currently 11. Then if we go ahead and add another comment, you'll see it gets updated down there in the feed and the total comments is updated to 12 with about maybe a second or so of latency. The latency is a little bit higher, but that is one of the trade offs when you're doing aggregation. So here we're looking at the post document in Firestore and you can see it's updated each time we add a new comment. If 99% of your users read the blog post but don't leave a comment, This is going to vastly reduce the number of reads that you execute in Firestore. Not only is that going to save you money as you gain more users, but it's also going to make your app much more performant. That's it for data aggregation with Firestore. If this video helped you, please like and subscribe. And, if you want twice as much content every week, Consider becoming a pro subscriber at angularfirebase.com. You'll get a free copy of my book as well as an extra video every week. And I even provide 1 on 1 port via our Slack team. Thanks for watching and I'll see you next time.
Are
are
you
you
interested
interested
in
in
retrieving
retrieving
data
data
from
from
the
the
Firestore
firestore
database
database
in
in
a
a
way
way
that's
that's
both
both
faster
faster
and
and
more
more
cost
cost
effective?
effective
If
if
so,
so
you're
you're
watching
watching
the
the
right
right
video.
video
Today,
today
I'm
i'm
going
going
to
to
show
show
you
you
how
how
to
to
use
use
Firebase
firebase
Cloud
cloud
Functions
functions
to
to
automatically
automatically
aggregate
aggregate
or
or
add
add
up
up
information
information
from
from
a
a
sub
sub
collection
collection
and
and
then
then
write
write
it
it
to
to
its
its
parent
parent
document.
document
Take
take
for
for
example
example
a
a
post
post
document
document
that
that
has
has
a
a
comment
comment
sub
sub
collection
collection
nested
nested
under
under
it.
it
Whenever
whenever
a
a
new
new
comment
comment
is
is
created,
created
it's
it's
going
going
to
to
trigger
trigger
a
a
cloud
cloud
function
function
that
that
will
will
read
read
this
this
comment
comment
sub
sub
collection,
collection
then
then
add
add
up
up
the
the
comment
comment
count
count
and
and
the
the
5
5
most
most
recent
recent
comments,
comments
and
and
then
then
duplicate
duplicate
them
them
on
on
the
the
post
post
document.
document
On
on
a
a
NoSQL
nosql
document
document
database
database
like
like
Firestore,
firestore
duplication
duplication
is
is
perfectly
perfectly
acceptable.
acceptable
Imagine
imagine
if
if
we
we
had
had
a
a
post
post
with
with
a
a
100
100
comments.
comments
We'd
we'd
have
have
to
to
read
read
all
all
those
those
comments
comments
to
to
get
get
the
the
total
total
every
every
time
time
someone
someone
viewed
viewed
a
a
post.
post
Not
not
only
only
is
is
that
that
slower
slower
for
for
the
the
end
end
user,
user
but
but
it's
it's
also
also
gonna
gonna
cost
cost
a
a
lot
lot
more
more
money
money
as
as
your
your
app
app
scales
scales
up.
up
My
my
goal
goal
today
today
is
is
to
to
show
show
you
you
how
how
to
to
solve
solve
this
this
problem
problem
using
using
back
back
end
end
data
data
aggregation.
aggregation
If
if
you're
you're
new
new
here,
here
make
make
sure
sure
to
to
subscribe
subscribe
and
and
you
you
can
can
grab
grab
the
the
full
full
source
source
code
code
from
from
angularfirebasedot
angularfirebasedot
comm.
comm
I'm
i'm
going
going
to
to
be
be
starting
starting
from
from
a
a
brand
brand
new
new
Angular
angular
app,
app
so
so
run
run
ng
ng
new.
new
Its
its
only
only
dependency
dependency
is
is
AngularFire
angularfire
2,
2
and
and
you
you
can
can
follow
follow
the
the
setup
setup
instructions
instructions
for
for
that
that
on
on
the
the
main
main
repo.
repo
If
if
you're
you're
not
not
using
using
Angular,
angular
you
you
can
can
skip
skip
ahead
ahead
to
to
the
the
Cloud
cloud
Function
function
code,
code
which
which
is
is
just
just
written
written
in
in
plain
plain
JavaScript.
javascript
The
the
first
first
thing
thing
I'll
i'll
show
show
you
you
is
is
our
our
underlying
underlying
data.
data
We
we
have
have
a
a
post
post
collection
collection
and
and
then
then
this
this
test
test
post
post
under
under
it.
it
Then
then
you
you
can
can
see
see
we
we
have
have
a
a
recent
recent
comments
comments
array
array
here,
here
which
which
is
is
the
the
5
5
most
most
recent
recent
comments
comments
from
from
potentially
potentially
100
100
or
or
even
even
1000
1000
of
of
comments
comments
in
in
the
the
sub
sub
collection.
collection
Having
having
this
this
data
data
on
on
the
the
parent
parent
doc
doc
is
is
extremely
extremely
useful
useful
if
if
you
you
loop
loop
through
through
a
a
list
list
of
of
posts
posts
and
and
you
you
just
just
wanna
wanna
show
show
quick
quick
preview
preview
of
of
the
the
most
most
recent
recent
comment
comment
as
as
well
well
as
as
the
the
total
total
comment
comment
count.
count
The
the
comment
comment
sub
sub
collection
collection
is
is
very
very
simple.
simple
It
it
just
just
has
has
a
a
content
content
property
property
and
and
a
a
created
created
at
at
timestamp.
timestamp
At
at
this
this
point,
point
I
i
wanna
wanna
point
point
out
out
that
that
this
this
is
is
not
not
suitable
suitable
for
for
every
every
situation.
situation
It's
it's
ideal
ideal
when
when
you
you
have
have
documents
documents
that
that
receive
receive
many
many
reads
reads
but
but
not
not
very
very
many
many
writes.
writes
A
a
good
good
example
example
would
would
be
be
Yelp,
yelp
where
where
many
many
users
users
want
want
to
to
see
see
the
the
reviews
reviews
for
for
a
a
location,
location
but
but
only
only
a
a
small
small
percentage
percentage
actually
actually
write
write
a
a
review.
review
Getting
getting
back
back
to
to
Angular,
angular
you're
you're
going
going
to
to
need
need
to
to
run
run
Firebase
firebase
init
init
functions
functions
if
if
you're
you're
in
in
a
a
new
new
project.
project
And
and
then,
then
we're
we're
not
not
going
going
to
to
install
install
anything
anything
special,
special
we
we
can
can
just
just
use
use
the
the
default
default
packages.
packages
But
but
make
make
sure
sure
they're
they're
updated
updated
to
to
the
the
newest
newest
version
version
because
because
Firestore
firestore
is
is
a
a
relatively
relatively
new
new
product.
product
We'll
we'll
write
write
this
this
Cloud
cloud
Function
function
in
in
a
a
few
few
minutes.
minutes
Let's
let's
first
first
make
make
the
the
query
query
without
without
any
any
data
data
aggregation.
aggregation
I
i
am
am
switching
switching
over
over
to
to
the
the
App
app
component,
component
and
and
then
then
I'm
i'm
going
going
to
to
import
import
Observable
observable
from
from
RxJS
rxjs
as
as
well
well
as
as
AngularFirestore.
angularfirestore
Then
then
I
i
can
can
go
go
ahead
ahead
and
and
inject
inject
AngularFirestore
angularfirestore
in
in
the
the
constructor.
constructor
From
from
there,
there
I'll
i'll
declare
declare
a
a
variable
variable
for
for
our
our
post
post
reference,
reference
which
which
is
is
an
an
AngularFirestore
angularfirestore
document,
document
and
and
then
then
we'll
we'll
set
set
another
another
variable
variable
for
for
the
the
observable.
observable
And
and
we'll
we'll
do
do
the
the
exact
exact
same
same
thing
thing
here
here
for
for
the
the
comments,
comments
but
but
it'll
it'll
be
be
an
an
AngularFirestore
angularfirestore
collection.
collection
Then
then
we'll
we'll
add
add
one
one
more
more
variable
variable
for
for
form
form
value
value
which
which
we'll
we'll
get
get
from
from
the
the
form
form
input
input
in
in
the
the
HTML.
html
During
during
ng
ng
on
on
init,
init
we'll
we'll
first
first
make
make
a
a
reference
reference
to
to
the
the
document
document
that
that
we
we
want,
want
which
which
in
in
this
this
case
case
is
is
just
just
called
called
testPost.
testpost
And
and
then
then
we
we
can
can
make
make
a
a
reference
reference
to
to
its
its
comment
comment
sub
sub
collection
collection
by
by
calling
calling
Collection
collection
on
on
that
that
reference.
reference
So
so
we
we
say
say
post
post
ref
ref
collection
collection
comments.
comments
And
and
it's
it's
also
also
important
important
that
that
we
we
order
order
by
by
something.
something
In
in
this
this
case,
case
we
we
have
have
a
a
timestamp
timestamp
on
on
the
the
comments.
comments
So
so
we'll
we'll
say
say
order
order
by
by
created
created
at
at
and
and
make
make
that
that
descending.
descending
Then
then
to
to
actually
actually
retrieve
retrieve
our
our
post,
post
we
we
call
call
post
post
ref
ref
value
value
changes
changes
and
and
that
that
returns
returns
it
it
as
as
an
an
observable.
observable
Then
then
we
we
can
can
do
do
the
the
exact
exact
same
same
thing
thing
for
for
comments.
comments
Then
then
we're
we're
going
going
to
to
switch
switch
over
over
to
to
the
the
HTML
html
and
and
we'll
we'll
set
set
a
a
template
template
variable
variable
for
for
our
our
post.
post
So
so
we
we
unwrap
unwrap
that
that
with
with
the
the
async
async
pipe
pipe
and
and
then
then
say
say
'as
'as
post'.
post'
And
and
then
then
from
from
there
there
we'll
we'll
just
just
display
display
the
the
post
post
title
title
and
and
the
the
post
post
Content.
content
Then
then
we'll
we'll
go
go
ahead
ahead
and
and
set
set
up
up
a
a
form
form
input
input
here
here
and
and
bind
bind
it
it
with
with
'ngmodel'.
'ngmodel'
Then
then
when
when
the
the
user
user
hits
hits
the
the
enter
enter
key,
key
we'll
we'll
go
go
ahead
ahead
and
and
and
and
run
run
a
a
function
function
to
to
update
update
that
that
in
in
the
the
database.
database
Right
right
now
now
we
we
have
have
a
a
comments
comments
observable,
observable
so
so
we'll
we'll
go
go
ahead
ahead
and
and
loop
loop
over
over
that
that
with
with
the
the
async
async
pipe.
pipe
But
but
after
after
we
we
perform
perform
some
some
data
data
aggregation,
aggregation
we'll
we'll
be
be
able
able
to
to
read
read
this
this
information
information
directly
directly
from
from
the
the
post
post
document.
document
So
so
at
at
this
this
point
point
we
we
have
have
our
our
Log
log
Post
post
here
here
and
and
then
then
the
the
user
user
can
can
enter
enter
their
their
comment
comment
and
and
it's
it's
updated
updated
in
in
real
real
time.
time
The
the
problem
problem
here
here
is
is
we're
we're
reading
reading
multiple
multiple
documents
documents
when
when
we
we
could
could
only
only
just
just
read
read
1,
1
and
and
we
we
also
also
don't
don't
have
have
an
an
efficient
efficient
way
way
to
to
keep
keep
track
track
of
of
a
a
comment
comment
count
count
or
or
any
any
other
other
aggregate
aggregate
data.
data
So
so
let's
let's
go
go
ahead
ahead
and
and
solve
solve
this
this
by
by
writing
writing
a
a
Cloud
cloud
Function.
function
We're
we're
going
going
to
to
import
import
the
the
admin
admin
database
database
and
and
make
make
sure
sure
that's
that's
initialized.
initialized
Then
then
we're
we're
going
going
to
to
run
run
the
the
function
function
whenever
whenever
a
a
new
new
comment
comment
document
document
is
is
written
written
to
to
the
the
database.
database
So
so
we
we
do
do
that
that
by
by
saying
saying
functions
functions
Firestore
firestore
document,
document
then
then
point
point
it
it
to
to
the
the
comment
comment
ID
id
nested
nested
under
under
the
the
post.
post
Using
using
on
on
right
right
will
will
run
run
this
this
function
function
whenever
whenever
a
a
document
document
is
is
created,
created
updated,
updated
or
or
deleted.
deleted
First,
first
we'll
we'll
set
set
a
a
couple
couple
variables
variables
here
here
for
for
the
the
comment
comment
ID
id
and
and
the
the
post
post
ID.
id
So
so
we
we
do
do
that
that
by
by
calling
calling
event
event
params
params
with
with
the
the
corresponding
corresponding
ID.
id
Then
then
after
after
we
we
have
have
those
those
IDs,
ids
we'll
we'll
set
set
up
up
a
a
reference
reference
2,
2
the
the
post
post
document.
document
We're
we're
going
going
to
to
do
do
that
that
with
with
the
the
admin
admin
database,
database
which
which
will
will
allow
allow
us
us
to
to
bypass
bypass
any
any
Firestore
firestore
rules
rules
that
that
we
we
have
have
set
set
up.
up
Then
then
from
from
there,
there
we
we
need
need
to
to
query
query
the
the
collection
collection
of
of
comments
comments
that
that
are
are
nested
nested
under
under
this
this
document
document
so
so
we
we
can
can
add
add
them
them
up
up
and
and
aggregate
aggregate
them.
them
In
in
a
a
Cloud
cloud
Function,
function
we're
we're
using
using
the
the
main
main
Firebase
firebase
SDK
sdk
as
as
opposed
opposed
to
to
AngularFire
angularfire
2,
2
so
so
we
we
do
do
things
things
slightly
slightly
different.
different
Instead
instead
of
of
calling
calling
value
value
changes,
changes
we
we
call
call
get.
get
That
that
returns
returns
a
a
promise
promise
with
with
the
the
query
query
snapshot.
snapshot
The
the
query
query
snapshot
snapshot
contains
contains
all
all
of
of
the
the
documents
documents
that
that
we
we
need,
need
and
and
it
it
behaves
behaves
kind
kind
of
of
like
like
an
an
array,
array
but
but
you
you
can't
can't
use
use
the
the
regular
regular
JavaScript
javascript
prototype
prototype
array
array
methods
methods
on
on
it.
it
To
to
get
get
the
the
size
size
of
of
the
the
collection,
collection
we
we
can
can
call
call
query
query
snapshot
snapshot
size.
size
And
and
then
then
to
to
get
get
all
all
of
of
the
the
recent
recent
comments,
comments
we'll
we'll
set
set
up
up
an
an
array
array
here.
here
Then
then
we
we
can
can
loop
loop
over
over
the
the
snapshots
snapshots
with
with
the
the
for
for
each
each
method,
method
and
and
for
for
each
each
comment,
comment
we're
we're
going
going
to
to
push
push
it
it
to
to
our
our
array.
array
At
at
this
this
point,
point
you
you
have
have
an
an
array
array
of
of
data
data
that
that
you
you
could
could
perform
perform
any
any
kind
kind
of
of
data
data
aggregation
aggregation
task
task
that
that
you
you
want.
want
But
but
for
for
now,
now
we're
we're
just
just
going
going
to
to
splice
splice
the
the
last
last
five
five
comments.
comments
And
and
we'll
we'll
also
also
set
set
a
a
property
property
for
for
the
the
last
last
activity,
activity
which
which
would
would
be
be
the
the
last
last
time
time
any
any
user
user
has
has
placed
placed
a
a
comment
comment
on
on
this
this
post.
post
And
and
then
then
finally,
finally
we
we
add
add
all
all
of
of
this
this
data
data
to
to
an
an
object,
object
then
then
we
we
can
can
call
call
update
update
on
on
our
our
document
document
reference.
reference
Then
then
we'll
we'll
also
also
go
go
ahead
ahead
and
and
console
console
log
log
errors
errors
here,
here
but
but
overall,
overall
it's
it's
a
a
pretty
pretty
simple
simple
cloud
cloud
function.
function
I'd
i'd
like
like
to
to
point
point
out
out
that
that
if
if
you're
you're
doing
doing
pull
pull
updates
updates
in
in
this
this
function.
function
You'd
you'd
want
want
to
to
wrap
wrap
it
it
in
in
either
either
a
a
transaction
transaction
or
or
do
do
them
them
all
all
in
in
a
a
single
single
batch.
batch
That
that
will
will
ensure
ensure
all
all
your
your
aggregate
aggregate
data
data
stays
stays
in
in
sync
sync
and
and
is
is
updated
updated
Tomically.
tomically
The
the
final
final
step
step
is
is
to
to
deploy
deploy
this
this
function
function
to
to
Firebase,
firebase
so
so
we
we
just
just
run
run
firebase
firebase
deploy
deploy
only
only
functions.
functions
Now
now
let's
let's
modify
modify
our
our
Angular
angular
app
app
to
to
take
take
advantage
advantage
of
of
this
this
function.
function
Back
back
in
in
the
the
App
app
component,
component
first
first
notice
notice
that
that
I've
i've
removed
removed
the
the
comments
comments
observable
observable
from
from
ngOnInit.
ngoninit
Instead,
instead
we're
we're
going
going
to
to
lazy
lazy
load
load
it
it
only
only
when
when
necessary.
necessary
Then
then
users
users
can
can
actually
actually
still
still
add
add
a
a
comment
comment
without
without
even
even
loading
loading
the
the
comments
comments
collection.
collection
Because
because
we
we
have
have
the
the
comments
comments
ref
ref
we
we
can
can
just
just
call
call
add
add
and
and
pass
pass
it
it
some
some
data.
data
We're
we're
going
going
to
to
show
show
the
the
user
user
the
the
first
first
five
five
comments,
comments
which
which
will
will
be
be
on
on
the
the
document.
document
If
if
the
the
user
user
wants
wants
to
to
load
load
more,
more
we'll
we'll
give
give
them
them
a
a
button
button
to
to
click,
click
which
which
will
will
lazily
lazily
populate
populate
the
the
comments
comments
observable.
observable
In
in
AngularFire
angularfire
2,
2
the
the
while
while
data
data
isn't
isn't
read
read
until
until
you
you
call
call
value
value
changes.
changes
Now
now
we
we
just
just
need
need
to
to
make
make
some
some
changes
changes
to
to
our
our
App
app
component
component
HTML
html
to
to
show
show
the
the
aggregate
aggregate
data.
data
So
so
first
first
up
up
here,
here
we'll
we'll
show
show
the
the
total
total
comment
comment
count
count
as
as
well
well
as
as
the
the
time
time
stamp
stamp
on
on
the
the
last
last
activity.
activity
Then
then
we'll
we'll
set
set
up
up
another
another
for
for
loop
loop
because
because
now
now
we
we
have
have
an
an
array
array
on
on
the
the
document
document
itself,
itself
but
but
we
we
only
only
wanna
wanna
show
show
this
this
if
if
the
the
comments
comments
observable
observable
isn't
isn't
populated.
populated
So
so
we
we
can
can
just
just
do
do
n
n
g
g
f
f
no
no
comments
comments
observable,
observable
then
then
we'll
we'll
go
go
ahead
ahead
and
and
show
show
the
the
5
5
most
most
recent
recent
comments.
comments
This
this
data
data
is
is
already
already
unwrapped
unwrapped
by
by
the
the
post
post
observable,
observable
so
so
we
we
can
can
just
just
call
call
post
post
recent
recent
comments
comments
and
and
we
we
don't
don't
need
need
to
to
use
use
the
the
async
async
pipe.
pipe
And
and
then
then
we'll
we'll
just
just
go
go
ahead
ahead
and
and
display
display
the
the
same
same
exact
exact
data.
data
If
if
the
the
user
user
decides
decides
they
they
want
want
to
to
load
load
all
all
of
of
the
the
comments,
comments
then
then
we'll
we'll
give
give
them
them
a
a
button
button
down
down
here
here
to
to
do
do
so.
so
So
so
we'll
we'll
just
just
say
say
click
click
and
and
then
then
run
run
our
our
load
load
more
more
event
event
handler
handler
and
and
we
we
can
can
show
show
them
them
how
how
many
many
comments
comments
are
are
on
on
this
this
post.
post
In
in
the
the
app
app
itself,
itself
take
take
a
a
look
look
at
at
the
the
total
total
comments
comments
which
which
is
is
currently
currently
11.
11
Then
then
if
if
we
we
go
go
ahead
ahead
and
and
add
add
another
another
comment,
comment
you'll
you'll
see
see
it
it
gets
gets
updated
updated
down
down
there
there
in
in
the
the
feed
feed
and
and
the
the
total
total
comments
comments
is
is
updated
updated
to
to
12
12
with
with
about
about
maybe
maybe
a
a
second
second
or
or
so
so
of
of
latency.
latency
The
the
latency
latency
is
is
a
a
little
little
bit
bit
higher,
higher
but
but
that
that
is
is
one
one
of
of
the
the
trade
trade
offs
offs
when
when
you're
you're
doing
doing
aggregation.
aggregation
So
so
here
here
we're
we're
looking
looking
at
at
the
the
post
post
document
document
in
in
Firestore
firestore
and
and
you
you
can
can
see
see
it's
it's
updated
updated
each
each
time
time
we
we
add
add
a
a
new
new
comment.
comment
If
if
99%
99%
of
of
your
your
users
users
read
read
the
the
blog
blog
post
post
but
but
don't
don't
leave
leave
a
a
comment,
comment
This
this
is
is
going
going
to
to
vastly
vastly
reduce
reduce
the
the
number
number
of
of
reads
reads
that
that
you
you
execute
execute
in
in
Firestore.
firestore
Not
not
only
only
is
is
that
that
going
going
to
to
save
save
you
you
money
money
as
as
you
you
gain
gain
more
more
users,
users
but
but
it's
it's
also
also
going
going
to
to
make
make
your
your
app
app
much
much
more
more
performant.
performant
That's
that's
it
it
for
for
data
data
aggregation
aggregation
with
with
Firestore.
firestore
If
if
this
this
video
video
helped
helped
you,
you
please
please
like
like
and
and
subscribe.
subscribe
And,
and
if
if
you
you
want
want
twice
twice
as
as
much
much
content
content
every
every
week,
week
Consider
consider
becoming
becoming
a
a
pro
pro
subscriber
subscriber
at
at
angularfirebase.com.
angularfirebase.com
You'll
you'll
get
get
a
a
free
free
copy
copy
of
of
my
my
book
book
as
as
well
well
as
as
an
an
extra
extra
video
video
every
every
week.
week
And
and
I
i
even
even
provide
provide
1
1
on
on
1
1
port
port
via
via
our
our
Slack
slack
team.
team
Thanks
thanks
for
for
watching
watching
and
and
I'll
i'll
see
see
you
you
next
next
time.
time
success
The speakers discuss using obtain data from Fir analysis for faster and cost-effective ways to write back to a document. They explain how to use the Cloud functions and the underlying data in the post collection, as well as solving the problem of multiple documents being read at once. They also discuss updating package packages for a Cloud function, setting variables, calling a query, and modifying the Angular app to take advantage of the function. They offer tips for improving performance and mention a free book and promotion for a book and video.
Faster Firestore via Data Aggregation
Are you interested in retrieving data from the Firestore database in a way that's both faster and more cost effective? If so, you're watching the right video. Today, I'm going to show you how to use Firebase Cloud Functions to automatically aggregate or add up information from a sub collection and then write it to its parent document. Take for example a post document that has a comment sub collection nested under it. Whenever a new comment is created, it's going to trigger a cloud function that will read this comment sub collection, then add up the comment count and the 5 most recent comments, and then duplicate them on the post document. On a NoSQL document database like Firestore, duplication is perfectly acceptable. Imagine if we had a post with a 100 comments. We'd have to read all those comments to get the total every time someone viewed a post. Not only is that slower for the end user, but it's also gonna cost a lot more money as your app scales up. My goal today is to show you how to solve this problem using back end data aggregation. If you're new here, make sure to subscribe and you can grab the full source code from angularfirebasedot comm. I'm going to be starting from a brand new Angular app, so run ng new. Its only dependency is AngularFire 2, and you can follow the setup instructions for that on the main repo. If you're not using Angular, you can skip ahead to the Cloud Function code, which is just written in plain JavaScript. The first thing I'll show you is our underlying data. We have a post collection and then this test post under it. Then you can see we have a recent comments array here, which is the 5 most recent comments from potentially 100 or even 1000 of comments in the sub collection. Having this data on the parent doc is extremely useful if you loop through a list of posts and you just wanna show quick preview of the most recent comment as well as the total comment count. The comment sub collection is very simple. It just has a content property and a created at timestamp. At this point, I wanna point out that this is not suitable for every situation. It's ideal when you have documents that receive many reads but not very many writes. A good example would be Yelp, where many users want to see the reviews for a location, but only a small percentage actually write a review. Getting back to Angular, you're going to need to run Firebase init functions if you're in a new project. And then, we're not going to install anything special, we can just use the default packages. But make sure they're updated to the newest version because Firestore is a relatively new product. We'll write this Cloud Function in a few minutes. Let's first make the query without any data aggregation. I am switching over to the App component, and then I'm going to import Observable from RxJS as well as AngularFirestore. Then I can go ahead and inject AngularFirestore in the constructor. From there, I'll declare a variable for our post reference, which is an AngularFirestore document, and then we'll set another variable for the observable. And we'll do the exact same thing here for the comments, but it'll be an AngularFirestore collection. Then we'll add one more variable for form value which we'll get from the form input in the HTML. During ng on init, we'll first make a reference to the document that we want, which in this case is just called testPost. And then we can make a reference to its comment sub collection by calling Collection on that reference. So we say post ref collection comments. And it's also important that we order by something. In this case, we have a timestamp on the comments. So we'll say order by created at and make that descending. Then to actually retrieve our post, we call post ref value changes and that returns it as an observable. Then we can do the exact same thing for comments. Then we're going to switch over to the HTML and we'll set a template variable for our post. So we unwrap that with the async pipe and then say 'as post'. And then from there we'll just display the post title and the post Content. Then we'll go ahead and set up a form input here and bind it with 'ngmodel'. Then when the user hits the enter key, we'll go ahead and and run a function to update that in the database. Right now we have a comments observable, so we'll go ahead and loop over that with the async pipe. But after we perform some data aggregation, we'll be able to read this information directly from the post document. So at this point we have our Log Post here and then the user can enter their comment and it's updated in real time. The problem here is we're reading multiple documents when we could only just read 1, and we also don't have an efficient way to keep track of a comment count or any other aggregate data. So let's go ahead and solve this by writing a Cloud Function. We're going to import the admin database and make sure that's initialized. Then we're going to run the function whenever a new comment document is written to the database. So we do that by saying functions Firestore document, then point it to the comment ID nested under the post. Using on right will run this function whenever a document is created, updated, or deleted. First, we'll set a couple variables here for the comment ID and the post ID. So we do that by calling event params with the corresponding ID. Then after we have those IDs, we'll set up a reference 2, the post document. We're going to do that with the admin database, which will allow us to bypass any Firestore rules that we have set up. Then from there, we need to query the collection of comments that are nested under this document so we can add them up and aggregate them. In a Cloud Function, we're using the main Firebase SDK as opposed to AngularFire 2, so we do things slightly different. Instead of calling value changes, we call get. That returns a promise with the query snapshot. The query snapshot contains all of the documents that we need, and it behaves kind of like an array, but you can't use the regular JavaScript prototype array methods on it. To get the size of the collection, we can call query snapshot size. And then to get all of the recent comments, we'll set up an array here. Then we can loop over the snapshots with the for each method, and for each comment, we're going to push it to our array. At this point, you have an array of data that you could perform any kind of data aggregation task that you want. But for now, we're just going to splice the last five comments. And we'll also set a property for the last activity, which would be the last time any user has placed a comment on this post. And then finally, we add all of this data to an object, then we can call update on our document reference. Then we'll also go ahead and console log errors here, but overall, it's a pretty simple cloud function. I'd like to point out that if you're doing pull updates in this function. You'd want to wrap it in either a transaction or do them all in a single batch. That will ensure all your aggregate data stays in sync and is updated Tomically. The final step is to deploy this function to Firebase, so we just run firebase deploy only functions. Now let's modify our Angular app to take advantage of this function. Back in the App component, first notice that I've removed the comments observable from ngOnInit. Instead, we're going to lazy load it only when necessary. Then users can actually still add a comment without even loading the comments collection. Because we have the comments ref we can just call add and pass it some data. We're going to show the user the first five comments, which will be on the document. If the user wants to load more, we'll give them a button to click, which will lazily populate the comments observable. In AngularFire 2, the while data isn't read until you call value changes. Now we just need to make some changes to our App component HTML to show the aggregate data. So first up here, we'll show the total comment count as well as the time stamp on the last activity. Then we'll set up another for loop because now we have an array on the document itself, but we only wanna show this if the comments observable isn't populated. So we can just do n g f no comments observable, then we'll go ahead and show the 5 most recent comments. This data is already unwrapped by the post observable, so we can just call post recent comments and we don't need to use the async pipe. And then we'll just go ahead and display the same exact data. If the user decides they want to load all of the comments, then we'll give them a button down here to do so. So we'll just say click and then run our load more event handler and we can show them how many comments are on this post. In the app itself, take a look at the total comments which is currently 11. Then if we go ahead and add another comment, you'll see it gets updated down there in the feed and the total comments is updated to 12 with about maybe a second or so of latency. The latency is a little bit higher, but that is one of the trade offs when you're doing aggregation. So here we're looking at the post document in Firestore and you can see it's updated each time we add a new comment. If 99% of your users read the blog post but don't leave a comment, This is going to vastly reduce the number of reads that you execute in Firestore. Not only is that going to save you money as you gain more users, but it's also going to make your app much more performant. That's it for data aggregation with Firestore. If this video helped you, please like and subscribe. And, if you want twice as much content every week, Consider becoming a pro subscriber at angularfirebase.com. You'll get a free copy of my book as well as an extra video every week. And I even provide 1 on 1 port via our Slack team. Thanks for watching and I'll see you next time.
The speakers discuss using obtain data from Fir analysis for faster and cost-effective ways to write back to a document. They explain how to use the Cloud functions and the underlying data in the post collection, as well as solving the problem of multiple documents being read at once. They also discuss updating package packages for a Cloud function, setting variables, calling a query, and modifying the Angular app to take advantage of the function. They offer tips for improving performance and mention a free book and promotion for a book and video.