0

I'm using Firebase scheduled function to periodically check data in Firestore if users' detail are added to SendGrid contact list. After they're successfully added to SendGrid, I want to update the value in firestore addToContact from false to true.

exports.addContact = functions.region(region).pubsub.schedule('every 4 minutes').onRun(async(context) => {
 
  // Query data from firestore
  const querySnapshot = await admin.firestore().collection('users')
        .where('metadata.addToContact', '==', false)
        .get();
 
 // Call SendGrid API to add contact

 // If success, change metadata.addToContact to true

 if (response) {
   const docRef = admin.firestore().collection('users').doc(""+context.params.id);
   await docRef.update( {'metadata.sendToSg': true }, { merge: true } );
 }
}

I want to access context.params.id but I realise that context that passed in .onRun isn't the same with the context passed in a callable function.

NOTE: If I pass context.params.id to .doc without ""+, I got an error Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string. After google the answer, I tried using ""+context.params.id then I can console.log the context value. I only got

context {
  eventId: '<eventID>',
  timestamp: '2020-11-21T09:05:38.861Z',
  eventType: 'google.pubsub.topic.publish',
  params: {}
}

I thought I'd get document ID from params object here but it's empty.

Is there a way to get Document ID from firestore in a scheduled function?

Renaud Tarnec
  • 79,263
  • 10
  • 95
  • 121
namwa
  • 45
  • 4

1 Answers1

1

The scheduled Cloud Function itself has no notion of a Firestore document ID since it is triggered by the Google Cloud Scheduler and not by an event occurring on a Firestore document. This is why the corresponding context object is different from the context object of a Firestore triggered Cloud Function.

I understand that you want to update the unique document corresponding to your first query (admin.firestore().collection('users').where('metadata.addToContact', '==', false).get();).

If this understanding is correct, do as follows:

exports.addContact = functions.region(region).pubsub.schedule('every 4 minutes').onRun(async (context) => {

    // Query data from firestore
    const querySnapshot = await admin.firestore().collection('users')
        .where('metadata.addToContact', '==', false)
        .get();

    // Call SendGrid API to add contact

    // If success, change metadata.addToContact to true

    if (response) {
        const docRef = querySnapshot.docs[0].ref;
        await docRef.update({ 'metadata.sendToSg': true }, { merge: true });
        
    } else {
        console.log('No response');
    }
    return null;

});

Update following your comment:

You should not use async/await with forEach(), see here for more details. Use Promise.all() instead, as follows:

exports.addContact = functions.region(region).pubsub.schedule('every 4 minutes').onRun(async (context) => {

    // Query data from firestore
    const querySnapshot = await admin.firestore().collection('users')
        .where('metadata.addToContact', '==', false)
        .get();

    // Call SendGrid API to add contact

    // If success, change metadata.addToContact to true

    if (response) {

        const promises = [];

        querySnapshot.forEach((doc) => {
            const { metadata } = doc.data();
            if (metadata.sendToSg == false) {
                promises.push(doc.ref.update({ 'metadata.sendToSg': true }, { merge: true }));
            }
        })

        await Promise.all(promises);

    } else {
        console.log('No response');
    }
    return null;

});
Renaud Tarnec
  • 79,263
  • 10
  • 95
  • 121
  • I would say it works as this has given me the idea to loop through the docs as I need to update many of them. I can access the doc.id this way. (`if (response) { querySnapshot.forEach(async(doc) => { const { metadata } = doc.data(); if (metadata.sendToSg == false) { const docRef = admin.firestore().collection('users').doc(doc.id); await docRef.update( {'metadata.sendToSg': true }, { merge: true } ); } }) }`) – namwa Nov 21 '20 at 19:20
  • See the update. BTW, if my answer gives you the solution to your problem, please accept it (see https://meta.stackexchange.com/a/5235). Thanks. – Renaud Tarnec Nov 21 '20 at 19:55