Chapter 22 - How to write trigger functions in Firebase Cloud Functions

In this chapter, we will learn how to create a function that basically acts a MySQL triggers.We will learn in depth how the onCreate, OnUpdate, OnWrite, OnDelete methods of Firebase Cloud Functions works. So we will understand this by an example,  whenever a Student takes a exam for subject, increase the counter of "Exams" in Student. A cloud function keeps an watch on document mentioned and whenever any action (crud) takes places, you can write your piece of action.

Now consider this the basic Student structure


And a basic subject structure


And you insert a data in Exam collection, whenever a student takes an exam of Subject with marks obtained. Now you update "totalexams" a counter field which shows total exams taken by student and a "totalmarks" fields which is summation of marks of all Exams took by that Student.

So lets write a function onCreate for the Exam/{ExamID}. Before starting this, please read the basic installation and deploying functions from this Chapter No 21. Now in your functions/index.js


Below is the general initialization in the very beginning of js file

 const functions = require("firebase-functions");  
 const admin = require("firebase-admin");  
 admin.initializeApp();  
 const db = admin.firestore();  


Now below that you start writing your individual functions. lets write the first function

 exports.incrementExamCounter = functions.firestore  
   .document("Exam/{ExamID}")  
   .onCreate((change, context) => {  
        const ExamData = change.data(); //This is whole exam document that is added  
        const StudentID = ExamData.studentid; //This is studentid of exam document  
         //Below is the data to be updated  
        let UpdateStudentData = {  
            totalexams: admin.firestore.FieldValue.increment(1);  
         }  
        db.collection("Student").doc(StudentID)  
         .update(UpdateStudentData)  
         .then(() => {  
                 console.log("Exam counter in Student has been updated", StudentID);  
               }).catch(function (error) {  
                 console.log("Some error occurred while updating", error);  
               });  
   });  


So document inserted at a point Exam/{ExamID}and has a studentid field will increment totalexams fields in document with studentid as document id in Student Collection.


Now this was the example of onCreate method i.e if you update anything in same Exam document. it will not trigger. Consider "marks" in field Exam document updates later after student papers are evaluated. So in this case, you can use onUpdate method. So we will write second function below above first function.

 exports.incrementExamTotalMarks = functions.firestore  
   .document("Exam/{ExamID}")  
   .onUpdate((change, context) => {  
        const ExamData = change.data(); //This is whole exam document that is updated  
        const StudentID = ExamData.studentid; //This is studentid of exam document  
        const marks = ExamData.marks //This is the marks of student  
         //Below is the data to be updated  
        let UpdateStudentData = {  
            totalmarks: admin.firestore.FieldValue.increment(Number(marks));   
         }  
        db.collection("Student").doc(StudentID)  
         .update(UpdateStudentData)  
         .then(() => {  
                 console.log("Exam counter in Student has been updated", StudentID);  
               }).catch(function (error) {  
                 console.log("Some error occurred while updating", error);  
               });  
   });  


This will increment totalmarks field




Now this same onUpdate functionality can be made with onWrite. Let see this and understand what is difference in both of them and when to use what.

 exports.incrementExamTotalMarks = functions.firestore  
   .document("Exam/{ExamID}")  
   .onWrite((change, context) => {  
        const ExamData = change.after.data(); //here instead of change.data()  
        if(change.before.exists) {  
           //onUpdate //this means item existed before this trigger.  
           const OldExamData = change.before.data(); //this data holds old information  
           //This data you can use for condition like. decrement the old marks first and then increment the new marks. Otherwise in all updates, the total marks of student goes on incrementing. //We are not writing this code  
        } else {  
           //onCreate //this means this is newly created on.  
         }  
        const StudentID = ExamData.studentid; //This is studentid of exam document  
        const marks = ExamData.marks //This is the marks of student  
         //Below is the data to be updated  
        let UpdateStudentData = {  
            totalmarks: admin.firestore.FieldValue.increment(Number(marks));   
         }  
        db.collection("Student").doc(StudentID)  
         .update(UpdateStudentData)  
         .then(() => {  
                 console.log("Exam counter in Student has been updated", StudentID);  
               }).catch(function (error) {  
                 console.log("Some error occurred while updating", error);  
               });  
   });  


So you can see, the difference between onUpdate and onWrite functions. And in above example, we have not used OldExamData. But you can use as per your requirement. In this case as mentioned, with each update on Exam document, the student total marks will keep on increment. Like each update of 50 marks will keep on increasing student marks with 50. So by onWrite method, you can first decrement the old marks and then increment new marks. Let us know in comment section, if you want a separate chapter on this.

The onDelete function, we can subtract the marks of Student by following

 exports.incrementExamTotalMarks = functions.firestore  
   .document("Exam/{ExamID}")  
   .onDelete((change, context) => {  
        const ExamData = change.data(); //This is whole exam document that is updated  
        const StudentID = ExamData.studentid; //This is studentid of exam document  
        const marks = ExamData.marks //This is the marks of student  
         //Below is the data to be updated //Here we multiplied by -1 to make it negative and it will act as decrement.  
        let UpdateStudentData = {  
            totalmarks: admin.firestore.FieldValue.increment(-1 * Number(marks));   
         }  
        db.collection("Student").doc(StudentID)  
         .update(UpdateStudentData)  
         .then(() => {  
                 console.log("Exam counter in Student has been updated", StudentID);  
               }).catch(function (error) {  
                 console.log("Some error occurred while updating", error);  
               });  
   });  

Now functions are written in your local function/index.js. So moving on to deploy these functions to firebase. You can simply open your firebase folder and run following command for only deploying functions

 firebase deploy --only functions --project=yourprojectslug  


This will deploy your functions to Firebase Console. You can visiting your Firebase Functions Panel and see all the deployed functions and in Logs section you can see the all logs when functions are called.

Now suppose you want make change in only functions or add a new one and deploy that only then you can run following command

 firebase deploy --only functions:incrementExamTotalMarks --project=yourprojectslug  


To deploy more than one function

 firebase deploy --only functions:incrementExamCounter, functions:incrementExamTotalMarks --project=yourprojectslug  


So hope you are much clear how to write the Cloud Firestore Functions for different purpose. There is much more usage for cloud functions. We can have chapters on this. Please write in the comment section, if you want specific chapter on particular usage of Cloud Function. And please share this blog with all you techie friends.



Post a Comment

1 Comments