November 13, 2017

Getting started with Firestore and AngularFire2

Cloud Firestore

A few weeks ago, Google has released its new solution for building scalable cloud databases — the Cloud Firestore. It has some nice improvements in comparison to their previous database (which used to be called Firebase but is now referred to as ‘Realtime Database’), like better data structuring and a more powerful querying API. In this post I’m going to go through everything you need to get started with Cloud Firestore in Angular with the official AngularFire2 library. So let’s get started!

Setup

1. installation

First things first, let’s set up a project. In this tutorial we want to build a little blog app where a user can manage their blog posts and save them to Firestore. So let’s go ahead and create a new project:

Next thing we need to do is install the necessary packages and tools for our project.

In the first line we installed Firebase package itself plus AngularFire2, which is a wrapper that adds some neat Angular-specific features to Firebase. Those packages also include things like Firebase Authentication, Hosting etc. but for now we’re only concerned with Cloud Firestore.

2. Firebase console

In order to actually use Cloud Firestore we need to create a new Firebase project that our app can connect to. To do this, go to the firebase console, click on ‘add project’ and fill in your project name. Once your project is set up, click on the ‘Database’ tab and activate Cloud Firestore.

The Database will then prompt you to select a security rule setting:

security rule settings

For now we’ll go with “start in test mode” which allows everyone (including us) to read and write to our database. When your app goes to production you should definitely consider changing your security rules to something more sane (learn more about security rules here), but for our purposes this is good enough.

The last thing we need in our console is our config data. For this, go back to ‘Project Overview’ and click on ‘Add Firebase to your web app’. From the popup you’ll need to copy just the content of the config object. With that we can head back to our project.

3. project

Next we’ll need to provide the config to our Angular application. For this we’ll head to app/src/environment.ts  and create a field called firebase in which we’ll copy our config data, like this:

Lastly we have to pass this config data to AngularFire2. Add the following line to the imports of your app.module.ts:

Now we’re all set and done and can start building our Firestore app!

creating a CRUD service

We want to create a blog app where one can write posts (create), display them (read), rate them by giving likes (update) and deleting them again (delete). If you want to see the finished result, here is a live demo and a github repo

Let’s start by creating a component to manage our posts and a Firestore service to add them to our database.

The manage-posts-component will be used to create and delete posts, the view-posts will read and update them.

Next we need a model to define how our posts should look like. create a file called post.model.ts with the following content: 

We’ll add the likes later. Next let’s build a form in the manage-posts-component to create our posts.

The only thing left to set up is our post service that communicates with Firestore. But before that let’s first talk about how Firestore structures your data.

Firestore Data Structure

Firestore data is stored within a document. A document is very similar to a JSON Object – it contains fields which map to values. It has all the regular JSON data types like strings, numbers, booleans etc. plus some additional ones. Then there’s also collections. Collections are basically just lists of documents that organize your documents and group them together. The most important two rules to keep in mind about documents and collections are these:

  • every document has to be contained within a collection
  • You don’t need to manage collections — Collections are automatically created when you add the first document to them and deleted when they’re empty

So let’s get to structuring the data in our blog app. We want have a bunch of posts, so we’ll use a collection called ‘posts’ in which we’ll put our post-documents. So let’s get to implementing our post service:

first we need to pass AngularFirestore to the constructor:

(Don’t forget to import AngularFirestore into your module!)

Then we need to create a path name for to our collection:

With those two in place, we can access our Firestore collections and documents by writing:

Note that the document can then be accessed at the path  'posts/:postid' . Later we will get to how t o access the document ids. These collections and documents contain all the methods that we need to implement our CRUD operations, so let’s get started!

1. Saving Data

To save data to Firestore, we pass the data we want to store to the add method on the collection:

We can then call our newly created add method within save:

And that’s it! Our data can now be stored in Cloud Firestore. One thing to note here is that the add method creates a new document with an id generated by Cloud Firestore itself.  If you want to name the path yourself, you can do so by setting the document manually:

2. Reading Data

Now that we have saved the data, we also want to read it. One really nice thing about angularfire2 is is that it gives you the ability to stream your data and get it directly as an Observable. So let’s go through the different ways to get your data with angularfire2:

The simplest way to get your data is by calling the valueChanges() method, which returns you an observable stream of your requested data, so you can easily react on data updates in the backend. In code it looks like this:

Pretty straightforward, right? The drawback is that you only get the posts themselves without any metadata like their id, so you can’t actually make any updates to the documents themselves. ValueChanges()  is good if you just want to display your data, but most of the time you’ll need something more sophisticated.

If you want to update or delete your data after getting it, you’ll need to use snapshotChanges() . This method returns an Observable of type DocumentChangeAction[] , which contains a lot of interesting metadata such as whether the data change was due to an add,  remove or modify event. Moreover, it contains a DocumentSnapshot , which includes — among other information — the post’s data and ids. For now we’re only interested in the latter, so we’ll use Rx’s map-operator to convert the DocumentChangeAction[]  to a Post[] + id:

Also let’s change our post model to include an optional id:

Now we can get to displaying our data our our view-post-component. First get the data from our post service:

and then loop over it in our html:

(Sidenote: I’m using a little css framework for my styles called spectre.css for my styles, hence the style classes, in case you were wondering.)

3. Updating Data

Now that we can display our posts and reference their corresponding docs by their ids, we can easily build in the like-functionality. First let’s create an update method in our Post-Service.

Note that the update method only requires a Partial of Post, which allows us to only update a single field of the document, which is pretty handy. After that is done we can extend our Post model to contain a like-field:

Then we’ll fix the call of our add method so it initializes all posts with zero likes.

And add a like method that increases a post’s like counter by one.

Lastly we’ll add the like button to our html:

4. Deleting Data

Finally we want to be able to delete our posts. Implementing that will be just as easy as updating the data. First let’s write our deletion method into our post-service:

Note that we want to avoid calling the method “delete” because it is a reserved keyword in JavaScript that shouldn’t be used for identifiers (see here).

Just as with update, we need to add the remove method to our component:

And for the final step, we want to display our posts in a table and give each row a delete button to remove the corresponding post. Here’s how that looks like in code:

And that’s it! We sucessfully implemented CRUD operations with Firestore. Again, you can check out the live demo of the finished post app, or check out the source code on github.

Conclusion

As we have seen in this tutorial, it’s really fast and easy to get started with Cloud Firestore. Moreover, the AngularFire2 wrapper makes it a great fit for use in Angular projects.


Mark Kvetny

Entwickler bei thecodecampus

Leave a Reply

Your email address will not be published. Required fields are marked *