Those who follow my content know that I always use the good old Firebase Realtime Database in React applications. I am saying good old here, because there is this new cool kid on the block: Firebaseâs Cloud Firestore . It can be used as alternative to Firebaseâs Realtime Database . According to Googleâs documentation, there are four major advantages of using Cloud Firestore over Firebaseâs Realtime Database:
I experienced the first argument from a code perspective, but also when inspecting the database entries on my Firebase projectâs dashboard, because it shifts the focus from JSON to document-oriented database. You can read more about which database to choose in this comprehensive article that pivots Firebaseâs Cloud Firestore vs. Realtime Database .
Before I migrate my React tutorials and books from the older Realtime Database to Cloud Firestore, Iâd like to show you a straight forward migration path regarding the source code. Thatâs how you can still use all the educational content I have written about Firebase and Firebaseâs Realtime Database, but exchange the database with Firebaseâs Cloud Firestore. As a result, I am not building a React application with Cloud Firestore from scratch, but migrating a feature-rich React with Firebase application that uses Firebaseâs Realtime Database over to Firebaseâs Cloud Firestore. Both versions are accessible as source code on GitHub:
Except for the database, everything else stays the same; thus, everything else you learned from my previous React Firebase tutorials is still up-to-date. Before we start with migration, consider reading through this visual Firebase tutorial to set up your Firebase project with Cloud Firestore.
First, our project has a Firebase class that connects our React application with the Firebase API (e.g. authentication API, database API). It currently uses Firebaseâs Realtime Database:
The previous code snippet has all the lines highlighted that need to be changed for the Firestore migration. Itâs not much, because all the other authentication related code stays the same. Only the database setup changes when using Cloud Firestore and the API to read and write on user and message entities. Letâs exchange the setup first. The usual npm install firebase node package comes with the Cloud Firestore and Realtime Database, so we can exchange this one straight forward.
The set up for using timestamps, in this case for the createdData property for our message entities, has also changed slightly. Now, only the other previously highlighted sections have to change, to interact with the new Firestore instead of the Realtime Database.
Instead of working on references that are used to locate the JSON objects in Firebaseâs Realtime Database, Firestore introduces Collections (Lists, Arrays) and Documents (Item, Entity, Object). With these new concepts, we can use the usual CRUD (Create, Read, Update, Delete) Operations on them with with set, get, update, delete methods.
Cloud Firestore uses set and update methods to create and edit documents in the database. For instance, when you sign up to Firebase authentication, in our application, in the sign up form, we made sure to create a new user in the database.
It works the same as before with Cloud Firestore, because it offers the same method , where the set() method creates a new document in the Firestore database. If the document already exists, its content will be overwritten. If the document doesnât exist, it will be created.
However, as seen in the code snippet, Cloud Firestore comes with a merge option. If you are not sure whether your document already exists, pass the merge option to avoid overwriting the entire document. New content is merged into the entity if the entity is already there. We donât use the update() method because it fails if the document doesnât exist.
In our case, the merge operation makes sense because we canât be sure if a user is signing up for the first time or if theyâve signed up with a social login such as Google or Facebook. To handle this, we migrate our user creations for the social logins in the sign in form to use the merge option too.
Conduct the same migration for the Facebook and Twitter sign in methods. Then you can be assured that every time a user signs in with one of the available sign in methods, the latest properties from the authenticated user will be merged into the database user.
We have some more set and update methods that were used for the Realtime Database in our application, but they stay the same for the Firestore Database. Only the sign in and sign up methods have changed, because it is more convenient to always merge the latest authenticated user to our database user document.
After we have learned how to write data to Firestore with set, update, and merge, we need to know how to read data from Firestore as well. Letâs migrate all our React components that are reading data from the Realtime Database to read data from Firebaseâs Firestore, starting with the UserList component that looks for Firebaseâs Realtime Database like the following:
Firebaseâs Realtime Database always returns an object that represents your data. It doesnât matter whether you request a single entity or a list of entities. For instance, a list of entities would always be a dictionary of the entities accessible by their identifiers. Now, when using Cloud Firestore instead, transforming the data collection to a list of items is different:
The snapshot offers a forEach method to iterate through the collection (documents/entities). Unfortunately there are no map, reduce or filter methods. Using the forEach method, you can create your list of items and keep track of the identifier of the document too.
Identical to the Realtime Database, the Cloud Firestore is realtime as well. But it uses more common sense of creating the listener, which is just the return value of the function call that can be used in Reactâs other lifecycle method to remove the listener.
Now we have seen how this works for lists (collection) when using Firebaseâs Firestore, but not a single item (document)? Letâs see how the UserItem component fetches data with the new Firestore:
If there is a user coming from React Routerâs state, the user is not fetched again. But also not kept up to date with a Firebase realtime listener. Thatâs why unsubscribing the listener is a conditional operation. The data fetching doesnât look much different from the previous version, except the method names changed to onSnapshot() and data() .
Now we have seen how collections and single documents are read from Firestore, so we need to apply the same refactorings to our other React components from the application. For instance, the Messages component fetches our messages collection that we adjusted in the beginning in the Firebase class:
As for the other components using Firestore now, the transformation changes, subscribing to and unsubscribing from the listener, and a couple of property and method namings change, too. Everything else stays fairly the same as before.
Migrating a larger application from Firebaseâs Realtime Database to Firebase Cloud Firestore isnât that complex. The database layer with its setup and operations changes, but all the other Firebase features such as authentication, authorization, and hosting stay identical. Reading and writing data with the Firestore isnât much different from the Realtime Database, but it adds more convenience using a more elegant API and data structure with collections and documents. As an exercise, I encourage you to go through my Firebase + React tutorial and migrate it to Firestore to learn more.
Check out the official Firestore documentation to learn more about how it structures data, how to read and write data, and how to integrate it with more advanced features. You can also check out the Firebase Realtime Database project and the Firebase Cloud Firestore project on GitHub from the beginning of this tutorial.