Nuriddin
Nuriddin

Reputation: 45

How to update document in firebase cloud function

In my cloud function I want to update my document from 'dashboard' collection when a new student added to 'students' collection.

const getActiveStudents = () => {
return db.collection('/students/').where('status', '==', true).get().then(
    snapshot => {
        let studentsCount = snapshot.docs.length;
        db.collection('/dashboard/').where('type', '==', 'students').get().then(
            result => {
                if (result.docs.length === 0) {
                    db.collection('dashboard').add({
                        count: studentsCount,
                        type: 'students',
                        label: 'Active students'
                    });
                }else {
                    result.docs[0].ref.update({
                        count: studentsCount,
                        type: 'students',
                        label: 'Active students'
                    });
                }
                return result;
            }
        ).catch(error => {
            console.log(error);
        });
        return snapshot;
    }
).catch(error => {
    console.log(error);
})
}

exports.onChangesInStudents = functions.firestore.document('/students/{studentId}').onWrite(event => {
    getActiveStudents();
    return;
});

When I add a new student, instead of updating document it adds a new document to my 'dashboard' collection. How should I organize my code in order to properly update the quantity of students.

enter image description here

Upvotes: 1

Views: 16062

Answers (2)

Steven Ogwal
Steven Ogwal

Reputation: 802

When a function is triggered, you might want to get data from a document that was updated, or get the data prior to update.

You can get the prior data by using change.before.data(), which contains the document snapshot before the update.

Similarly, change.after.data() contains the document snapshot state after the update.

Node.js

exports.updateUser = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
    // Get an object representing the current document
    const newValue = change.after.data();

    // ...or the previous value before this update
    const previousValue = change.before.data();

    //...therefore update the document as.
    admin.firestore().collection('user').doc(docId).update(snapshot.after.data());

});

Reference:- https://firebase.google.com/docs/functions/firestore-events

Upvotes: 2

alp
alp

Reputation: 712

as @Doug mentioned, iterating over the entire collection is too heavy. instead you can stream the query results and iterate over keys, using query.stream().

to access and update a single field in a document, first retrieve the document by its ID with doc(), then use update() while specifying the field.

here's an example of implementation based on your scenario.

package.json

{
  "dependencies": {
    "firebase-admin": "^6.5.1",
    "firebase-functions": "^2.1.0"
  }
}

index.js

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp(functions.config().firebase);

const studentsRef = admin.firestore().collection('students');
const dashboardRef = admin.firestore().collection('dashboard');

exports.addStudent = functions.firestore
  .document('students/{studentId}')
  .onCreate((snap, context) => {
    var newStudent = snap.data();
    console.log('New student in collection: ', newStudent);

    var activeCount = 0;
    studentsRef.where('status', '==', true).select().stream()
      .on('data', () => {
        ++activeCount;     
      }).on('end', () => { 
        dashboardRef.where('type', '==', 'students').get()
          .then(querySnap => {
            if (querySnap.docs[0].data().count == activeCount){
              console.log('No new active student: ', querySnap.docs[0].data());
            } else {
                console.log('New active count: ', activeCount);
                console.log('Student Dashboard before update: ', querySnap.docs[0].id, '=>', querySnap.docs[0].data());
                dashboardRef.doc(querySnap.docs[0].id).update({
                  count: activeCount
                });
                console.log('Active student count updated: ', querySnap.docs[0].data().count, '=>', activeCount);
              };
            });
        });
  return null
  });

gcloud

gcloud functions deploy addStudent \
  --runtime nodejs8 \
  --trigger-event providers/cloud.firestore/eventTypes/document.create \
  --trigger-resource "projects/[PROJECT_ID]/databases/(default)/documents/students/{studentId}"

Upvotes: 4

Related Questions