Firebase Cloud Firestore Queries using Javascript(NodeJs)

Sajid Ahmed
7 min readJul 4, 2020

How To Save, Update And Delete Data In Firebase Cloud Firestore

Connection code with Firebase:

You will find this below code from your firebase project. Copy that code in your project folder to establish connection with firebase.

var firebase = require(“firebase/app”);// dependencies of firebase authenticationrequire(“firebase/auth”);
// dependencies of firebase firestore
require(“firebase/firestore”);require(“firebase/analytics”);// Your web app’s Firebase configurationvar firebaseConfig = {apiKey: “AIzaSyDsQW6XOLvacHCoCE4_aylbPnb0vqacyTI”,authDomain: “fir-app-f3d37.firebaseapp.com”,databaseURL: “https://fir-app-f3d37.firebaseio.com",projectId: “fir-app-f3d37”,storageBucket: “fir-app-f3d37.appspot.com”,messagingSenderId: “369290148095”,appId: “1:369290148095:web:dc3f12db73c3a98f3a74ca”};// Initialize Firebasefirebase.initializeApp(firebaseConfig);module.exports=firebase;

First off, we need to create a constant that holds the different Firestore functions needed for the different operations.

const database = firebase.firestore();

Save Data

const usersCollection = database.collection('users');function storeUserData(firstName,lastName,age) {

const ID = usersCollection.doc('user01').set({
first_name: firstName,
last_name: lastName,
age: age
})
.then(()=>{
console.log('Data has been saved successfully !')})
.catch(error => {
console.error(error)
});
}

The then and catch blocks are optional.

Add A Field To A Document

Let’s say we want to add data to a document. If we use set, all the data in that document will be overwritten. Therefore to prevent the old data loss, we need to add another parameter to the set method.

The second parameter of set is an object that has the merge property. merge needs to be set to true. Thus if we try to add another field to the document, it will overwrite only the field if it exists. If the field doesn’t already exist it will be added.

const usersCollection = database.collection('users');function storeUserData(firstName,lastName,age) {

const ID = usersCollection.doc('user01').set({
first_name: firstName,
last_name: lastName,
age: age
},{merge:true})
.then(()=>{
console.log('Data has been saved successfully !')})
.catch(error => {
console.error(error)
});
}

Auto-Generated IDs

Up until now we’ve been hard coding the documents identifiers. However, if we want them to be automatically generated we can use the add method instead of set.

const usersCollection = database.collection('users');function addUser(firstName,lastName,age) {

const ID = usersCollection.add({
first_name: firstName,
last_name: lastName,
age: age
});
});

Furthermore, we can store an identifier in a constant using the doc method without a parameter. Then use it later calling the set method on it.

const usersCollection = database.collection('users');function addUser(firstName,lastName,age) {

const ID = usersCollection.doc();
ID.set({
first_name: firstName.value,
last_name: lastName.value,
age: Number(age.value)
});
});

Update Data

To update data we should simply specify the document’s reference and use the update method. update takes an object that holds the new data as a parameter.

const usersCollection = database.collection('users');updateBtn.addEventListener('click', e => {
e.preventDefault();
usersCollection.doc(userId.value).update({
first_name: firstName.value,
last_name: lastName.value,
age: Number(age.value)
});
});

Update Objects

Updating an object is a bit tricky. If you thought that we could just specify the name of the field and set the new property. Well, that’s because all of the data in the object will be overwritten.

const usersCollection = database.collection('users');updateBtn.addEventListener('click', e => {
e.preventDefault();
usersCollection.doc(userId.value).update({
favorite: {
food: 'Pizza'
}
});
});

That being said, the right way of updating an object is to specify the name of the object, followed by a dot, then the name of the property.

const usersCollection = database.collection('users');updateBtn.addEventListener('click', e => {
e.preventDefault();
usersCollection.doc(userId.value).update({
'favorite.food': 'Pizza'
});
});

Update Arrays

Updating arrays is also quite different. As there are certain prebuilt functions to use in order to update this type of data.

So to add data to an array we should use the arrayUnion function.

//adding map data to arraysconst contactData = firebase.firestore().collection('ContactUs').doc(uid);contactData.set({UserContactData:
firebase.firestore.FieldValue.arrayUnion(contactDataMap)
},{merge:true})//adding value to arraysconst usersCollection = database.collection('users');
usersCollection.doc(userId.value).update({
favorite_color:
firebase.firestore.FieldValue.arrayUnion('Yellow')
});
//nesting arrays
const usersCollection = database.collection('users');values=['yesllow','green','red'];usersCollection.doc(userId.value).update({
favorite_colors:
firebase.firestore.FieldValue.arrayUnion.apply(null, values)
FieldValue.arrayUnion.apply(null, values)});

To delete data from an array we should use the arrayRemove function.

const usersCollection = database.collection('users');updateBtn.addEventListener('click', e => {
e.preventDefault();
usersCollection.doc(userId.value).update({
favorite_color: firebase.firestore.FieldValue.arrayRemove('Green')
});
});

Useful Functions

Firestore provides a handful of useful functions. serverTimestamp is one of them. This function returns the timestamp of the document’s update.

const usersCollection = database.collection('users');updateBtn.addEventListener('click', e => {
e.preventDefault();
usersCollection.doc(userId.value).update({
updated: firebase.firestore.FieldValue.serverTimestamp
});
});

increment is also a very helpful function that you can use to increment and decrement numeric values.

const usersCollection = database.collection('users');updateBtn.addEventListener('click', e => {
e.preventDefault();
usersCollection.doc(userId.value).update({
age: firebase.firestore.FieldValue.increment(8)
//decrement
//age: firebase.firestore.FieldValue.increment(-8)
});
});

Delete Data

Delete A Field

Deleting a field from within a document is considered an update. Therefore we need to use the update method, then call the delete function on the field we wish to remove.

const usersCollection = database.collection('users');updateBtn.addEventListener('click', e => {
e.preventDefault();
usersCollection.doc(userId.value).update({
favorites: firebase.firestore.FieldValue.delete()
});
});

Delete A Document

Deleting a document is also pretty easy. This time we just need to specify the document’s location and then call the delete method on it.

const usersCollection = database.collection('users');removeBtn.addEventListener('click', e => {
e.preventDefault();
usersCollection.doc(userId.value).delete();
});

How To Read Data In Firebase Cloud Firestore

The get Method

To read data from the database we need to use the get method on the reference of a document.

const usersCollection = database.collection('users');readBtn.addEventListener('click', e => {
e.preventDefault();
usersCollection.doc(userId.value).get()
.then(user => {
if(user.exists)
console.log(user.data());
else
console.log('User does not exist !');
})
.catch(error => {
console.error(error);
});
});

The exists property informs about the existence of the document. Because the nonexistence of a document doesn’t count as an error.

Now to get the data of all the documents within a collection. We need to use the get method directly on the collection’s reference.

const usersCollection = database.collection('users');readBtn.addEventListener('click', e => {
e.preventDefault();
usersCollection.get().then(snapshot => {
snapshot.forEach(user => {
console.log(user.id, ' => ', user.data());
});
})
.catch(error => {
console.error(error);
});
});

user.id returns the document’s identifier and user.data() returns the data within it.

Querying The Database

To query the database based on a field’s value as a criterion. We need to use the where method which is similar to the where clause in SQL databases.

So let’s say we want to query the database based on the value of the last_name field. Then, in this case, we should use the where method.

The first parameter should contain the field’s key. The second parameter is the querying operator. And finally, the third one is the value we want to query based on.

These are the 8 querying operators >, >=, ==, <, <=, in, array-contains, array-constains-any. Each is suitable for a certain need.

const usersCollection = database.collection('users');readBtn.addEventListener('click', e => {
e.preventDefault();
const query = usersCollection.where('last_name', '==', 'Yasmina');
query.get().then(snapshot => {
snapshot.forEach(user => {
console.log(user.id, ' => ', user.data());
});
})
.catch(error => {
console.error(error);
});
});

Furthermore, we can chain multiple queries. However the fields within the where calls in the query must be the same.

const usersCollection = database.collection('users');readBtn.addEventListener('click', e => {
e.preventDefault();
const query = usersCollection.where('age', '>', 18).where('age', '<=', 32);
query.get().then(snapshot => {
snapshot.forEach(user => {
console.log(user.id, ' => ', user.data());
});
})
.catch(error => {
console.error(error);
});
});

As you might have noticed in this example. I used the age field as a criterion in both of the where methods.

Querying Based On Array Values

Arrays, on the other hand, have special operators. Therefore to get documents that have a certain value in a field which must be an array. We should use the array-contains operator.

const usersCollection = database.collection('users');readBtn.addEventListener('click', e => {
e.preventDefault();
const query = usersCollection.where('favorite_languages', 'array-contains', 'Javascript');
query.get().then(snapshot => {
snapshot.forEach(user => {
console.log(user.id, ' => ', user.data());
});
})
.catch(error => {
console.error(error);
});
});

We can also get documents that have a value or more among other values that we specify in another array. That can be done through the array-contains-any method.

const usersCollection = database.collection('users');readBtn.addEventListener('click', e => {
e.preventDefault();
const languages = ['C', 'Java', 'Delphi', 'C++'];
const query = usersCollection.where('favorite_languages', 'array-contains-any', languages);
const query = usersCollection.where('age', '>=', 30).where('age', '<', 40);
query.get().then(snapshot => {
snapshot.forEach(user => {
console.log(user.id, ' => ', user.data());
});
})
.catch(error => {
console.error(error);
});
});

In this example, if a user has C, Java, Delphi or C++ in their favorite_languages field they should be selected.

Keep in mind that arrays that are set for the comparison can’t take any more than 10 values to search for.

Listeners In Firebase Cloud Firestore

Same as Firebase Realtime Database, we can attach listeners to the references in the database. So whenever an event occurs, a callback function gets triggered to execute whatever code you put inside of it. To so we need to use the onSnapshot method. Consequently, we can get the new data after the event using the data function.

usersCollection.doc('user01').onSnapshot(snapshot => {
console.log('Current data: ', snapshot.data());
}, error => {
console.log('Error !');
});

Furthermore, we can attach listeners to more than a single document using the where method.

usersCollection.where('last_name', '==', 'Doe').onSnapshot(snapshot => {
snapshot.forEach(user => {
console.log('The user with the ID ', user.id, ' has been updated/added/deleted');
});
});

We can also get the type of the event that occurred on the reference, through the type property for each document found by the where method.

usersCollection.where('age', '==', 44).onSnapshot(snapshot => {
snapshot.docChanges().forEach(change => {
if(change.type === 'added')
console.log('Add operation has been done !');
if(change.type === 'changed')
console.log('change operation has been done !');
if(change.type === 'removed')
console.log('Delete operation has been done !');
}, error => {
console.log(error);
});
});

The docChanges here is a function that returns an array, this array contains the list of changes that occurred on each the documents.

--

--