Cloud Firestore is great for building internal apps because it handles all the complicated ins and outs of managing a database for you. In this tutorial, we’ll show you how to set up a basic CRUD app with the Cloud Firestore using the Node.js SDK:
- Set up the Cloud Firestore Node.js SDK
- Create data
- Read data
- Update data
- Delete data
To get started, you’ll first need install the Node.js client library and initialize your instance of the database. You can install the library via npm with:
1npm install firebase-admin --save
2
Once the package is installed, you need to initialize the database. You can do this with Firebase Cloud Functions, the Google Cloud Platform, or through your own server. For this tutorial, we’re going to quickly show you how to initialize the database on your own server using a service account, which is an account identity used to make API requests to an application (learn more about service accounts here).
First, you’ll need to go to the Service Accounts menu in Google Cloud Platform account (it’s under IAM & Admin). From there, generate a new private key, save it as a JSON file, and add it to your server.
Then, in your index.js
file, include the firebase-admin
library and import your service account private key from your server. Use the firebase-admin
library to initialize your application, passing an object with credential
as the key and firestore.credential.cert()
(with your service account as an argument) as the value.
1const fs = require('firebase-admin');
2
3const serviceAccount = require('./path/to/key.json');
4
5fs.initializeApp({
6 credential: fs.credential.cert(serviceAccount)
7});
8
Finally, call the firestore()
amethod to create your database.
1const db = fs.firestore();
2
This wouldn’t be a CRUD tutorial without some sample data, so let’s get that out of the way. Imagine we’re building internal tools for an online retailer — let’s say a tool to show customer support reps some user data:
1{
2 "first": "Liam",
3 "last": "Ragozzine",
4 "address": "133 5th St., San Francisco, CA",
5 "birthday": "05/13/1990",
6 "age": "30"
7},
8{
9 "first": "Vanessa",
10 "last": "Peluso",
11 "address": "49 Main St., Tampa, FL",
12 "birthday": "11/30/1977",
13 "age": "47"
14}
15
This dataset is, of course, overly simplified - for more complex setups, there are a couple of options for structuring your data in Firestore:
- Documents
- Multiple collections
- Subcollections within documents
Each one has pros and cons that play into ease of use, scalability, and complexity. You can read more about structuring data in Cloud Firestore right here.
Got it? Great! Now for CRUD.
To fill our database, we’re going to use the set()
method. First, we’re going to specify that we want to fill the users
collection with the collection()
method. To do this, simply pass the name of the collection into the method as a string:
1const usersDb = db.collection('users');
2
Now, we need to specify the first document so we can add our new user, Liam Ragozzine. To do this, we’ll use the doc()
method. To use this method, pass the id
of the document into doc()
as a string. For this example, the id
is ‘lragozzine’.
1const liam = usersDb.doc('lragozzine');
2
After specifying the document we want to add, we can set the data for the document by passing the data as an object into set()
.
1await liam.set({
2 first: 'Liam',
3 last: 'Ragozzine',
4 address: '133 5th St., San Francisco, CA',
5 birthday: '05/13/1990',
6 age: '30'
7});
8
Awesome! Now, if we wanted to add our second user, it would look like this:
1await usersDb.doc('vpeluso').set({
2 first: 'Vanessa',
3 last: 'Peluso',
4 address: '49 Main St., Tampa, FL',
5 birthday: '11/30/1977',
6 age: '47'
7});
8
One important thing to note: the set()
method will overwrite a document if it already exists. We’ve been using .doc(ID)
to create new documents via set()
, but if a document with the passed ID already exists, the data you pass in .set()
will override whatever currently exists.
Now that we’ve got data in our database, we can move on to reading it.
To read your data from Firestore, use the get()
method. To read from a collection, specify a collection()
before calling get()
. Or, if you need to read from a document, specify a doc()
before calling get()
.
1// get collection
2const users = await db.collection('users').get();
3
4// get document
5const liam = await db.collection('users').doc('liam').get();
6
If the document doesn’t exist, the result will be empty. So in the above example, liam
would have no data. You can check this by calling exists on the doc. If the document exists
, it will return true and you can call data()
to read the data of the document. Otherwise, it will return false.
1if (!liam.exists) {
2 console.log('No document');
3} else {
4 console.log(liam.data());
5}
6
To filter (“query”) your results, you can use where()
, which takes three arguments:
- A field from the collection to test the value of
- Relational operator (like <, >, or == for example)
- The value for the first argument to be evaluated against
For example, if we wanted all documents for users who are younger than 40, we’d use the following:
1const under30 = await
2 db.collection('users').where('age', '<=', 40).get();
3
What’s really cool about Cloud Firestore is that you can get real-time updates on your data using the onSnapshot()
method. This lets you listen for changes to any of the documents in your database. After initializing the method and passing a callback function to handle the data, you’ll receive an update every time there’s a change to the content.
1const liam = db.collection('users').doc('liam');
2
3const observer = liam.onSnapshot(snapshot => {
4 console.log(`changes: ${snapshot}`);
5}, err => {
6 console.log(`Error: ${err}`);
7});
8
Now, your app is current with the latest trends. 😎
In Firestore there are two ways to update data: set()
or update()
. In short, using set()
will generally overwrite the entire document you’re working with, while update()
is best for updating particular fields while leaving others untouched.
Starting with set()
, if we wanted to make a note in Liam’s document that he is married, we would call set()
with the object { married: true }
. Like we mentioned above, it’s important to note that if you use set() on a document that already exists, you’ll overwrite it unless you specify merge: true
like this:
1const liam = await
2 db.collection('users').doc('lragozzine').set({
3 married: true
4 }, { merge: true });
5
Hint: If you’re not sure whether a document already exists, add merge
just in case, so you don’t overwrite your data.
To use the update()
method to update a field in a document, pass an object with the field you wish to update as an argument to update()
.
1const liam = await
2 db.collection('users').doc('lragozzine').update({
3 married: true
4 });
5
To update data in a nested object, you’ll also want to use update()
. If we wanted to add an object that contained key-value pairs about a customer’s favorite things (like favorite color, product line, or bad ’90s TV show), we would pass an object where the key is a path, like this:
1const liam = await
2 db.collection('users').doc('lragozzine').update({
3 'favorites.item': 'Ties'
4 });
5
Now that we know how to merge and update our documents, let’s move on to deleting.
This shouldn’t be a surprise: you delete data from Firestore using the delete()
method. It’ll look something like this:
1await db.collection('users').doc('lragozzine').delete();
2
This will delete Liam’s entire document from the users
database.
Note: If you delete a document, it will not delete the document’s subcollections. So if Liam had a subcollection in his document that contained documents with order data, called orders
, then even after deleting the lragozzine
document, we would still be able to access the subcollection orders
, like this:
1const liamOrders = await db.collection('users').doc('lragozzine')
2 .collection('orders').doc('123').get();
3
To delete a field, use FieldValue.delete()
in an update()
command. First, you must import the FieldValue
object, and then call delete()
on it, like this:
1const FieldValue = fs.firestore.FieldValue;
2
3const r = await
4 db.collection('users').doc('lragozzine').update({
5 married: FieldValue.delete();
6 });
7
Deleting entire collections gets a little more complicated because you have to make requests to retrieve all documents in a collection and delete them one by one. For more information on deleting collections, check out Firebase’s guide.
Congratulations! You’re now a Cloud Firestore CRUD expert.
Retool gives you a complete set powerful building blocks for building internal tools and CRUD apps: Assemble your app in 30 seconds by dragging and dropping from 50+ pre-built components. Connect to Firestore and dozens of data integrations and anything with a REST or GraphQL API, like a Firestore GUI. Get started for free👉
Reader