Taio
Taio

Reputation: 3724

Listen to changes in Root collection cloud function in firestore

Most of the examples i have seen explain how to listen to a document with the uid of a user.I am trying to listen to just the general parent collection

exports.sendNotifications = functions.firestore.document('Notifications').onCreate(async (snapshot) => {
    // Notification details.
    const payload = {
      notification: {
          title: 'Hello',
          body: 'Hello again',
        click_action: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com`,
      }
    };

    // Get the list of device tokens.
    const allTokens = await admin.firestore().collection('fcmTokens').get();
    const tokens = [];
    allTokens.forEach((tokenDoc) => {
      tokens.push(tokenDoc.id);
    });

    if (tokens.length > 0) {
      // Send notifications to all tokens.
      const response = await admin.messaging().sendToDevice(tokens, payload);

    }
  });

This cloud function brings functions: failed to create function sendNotifications HTTP Error: 400, The request has errors. The error I am guessing is because the firestore collection is not being referenced properly. It is the root collection. How can I reference it better

Upvotes: 1

Views: 1501

Answers (1)

Renaud Tarnec
Renaud Tarnec

Reputation: 83093

There are several points that you should modify in your Cloud Function:

1/ You should trigger it when a Document is created, as follows. See https://firebase.google.com/docs/functions/firestore-events?authuser=0#wildcards-parameters.

exports.sendNotifications = functions.firestore.document('Notifications/{notifId}')
    .onCreate(async (snap, context) => {

      const newValue = snap.data();

      // perform desired operations ...
      // You may not need the notifId value but you have to keep the wildcard in the document path
    });

2/ Also, note how onCreate() has a data and a context parameters. See https://firebase.google.com/docs/functions/firestore-events?authuser=0#trigger_a_function_when_a_new_document_is_created and https://firebase.google.com/docs/functions/beta-v1-diff?authuser=0#cloud-firestore for more details.

3/ Finally, you should return the promise returned by the admin.messaging() asynchronous task as well as returning a value in case tokens.length = 0. These two actions ensure you indicate to the platform that the work of the Cloud Function is finished. (I would suggest you watch the 3 videos about "JavaScript Promises" from the Firebase video series: https://firebase.google.com/docs/functions/video-series/)

So, at the end your code would look as follows. (Note that I've not tested it, so I cannot 100% guarantee that it will solve your "HTTP Error: 400, The request has errors" problem...)

exports.sendNotifications = functions.firestore.document('Notifications/{notifId}')
.onCreate(async (snap, context) => {
    // Notification details.
    const payload = {
      notification: {
          title: 'Hello',
          body: 'Hello again',
        click_action: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com`,
      }
    };

    // Get the list of device tokens.
    const allTokens = await admin.firestore().collection('fcmTokens').get();
    const tokens = [];
    allTokens.forEach((tokenDoc) => {
      tokens.push(tokenDoc.id);
    });

    if (tokens.length > 0) {
      // Send notifications to all tokens.
      return await admin.messaging().sendToDevice(tokens, payload);
    } else {
      return null;
    }
  });

Upvotes: 3

Related Questions