Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase Cloud Function to trigger Firebase Messaging not sending Notification

I want to send a PushNotification via Cloud Messaging when a document is added inside a collection of a user called notifications. I am saving the token for the user as suggested in the docs in a arrayUnion in a field called messagingTokens.

Additionally the notification should only be sent if a field called isPushEnabled is true. With this information I build this cloud function and successfully deployed it:

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const { onDocumentCreated } = require("firebase-functions/v2/firestore");
const { setGlobalOptions } = require("firebase-functions/v2");

admin.initializeApp();


// Set the maximum instances to 10 for all functions
setGlobalOptions({ maxInstances: 10 });

const notificationPath = "allUsers/{userId}/notifications/{notificationId}";
exports.sendNotification = onDocumentCreated(notificationPath, async (event) => {
    functions.logger.log("New notificatin document was created"); 
    const data = event.data.after.data();
    const senderUid = data.senderUid;
    const receiverUid = data.receiverUid;
    const notificationOption = data.option;
    functions.logger.log("Retrieved notification fields"); 

    if (notificationOption === "receivedFriendRequest") {
        functions.logger.log("Is option: receivedFriendRequest");
        await onSentFriendRequest(senderUid, receiverUid);
    }
});

async function onSentFriendRequest(ownerId, userId) {
    // Get the owners details
    const owner = await admin.firestore().collection("allUsers").doc(ownerId).get();

    // Get the users details
    const user = await admin.firestore().collection("allUsers").doc(userId).get();

    const userHasNotificationsEnabled = user.data().isPushEnabled;

    functions.logger.log("If this does not print, then your function is not being called");
    if (!userHasNotificationsEnabled) {
        functions.logger.log("User does not have push enabled");
        return;
    }
    functions.logger.log("User has push enabled");

    // Listing all tokens as an array.
    tokens = user.data().messagingTokens;

    // Send message to all tokens
    const response = await admin.messaging().sendEachForMulticast({
        tokens: tokens,
        notification: {
            title: "Neue Freundschaftsanfrage",
            body: `${owner.data().username} möchte mit dir befreundet sein.`,
        },
        data: {
            ownerId: ownerId,
            userId: userId,
            notificationOption: "receivedFriendRequest",
        },
    });

    // For each message check if there was an error.
    const tokensToRemove = [];
    response.results.forEach((result, index) => {
        const error = result.error;
        if (error) {
            functions.logger.error(
                'Failure sending notification to',
                tokens[index],
                error
            );
            // Cleanup the tokens who are not registered anymore.
            if (error.code === 'messaging/invalid-registration-token' ||
                error.code === 'messaging/registration-token-not-registered') {
                tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
            }
        }
    });
    return Promise.all(tokensToRemove);

}

Like I said, the deployment was successful. But when a document is added to the notifications-collection I get this from my logs:

Logs

Inside the Firebase-Console I see that the function was triggered, I get a TypeError.

What am I doing wrong here? Let me know if you need more information.

EDIT

I had an error about maxScale which I could fix by adding this line inside my index.js-file:

    setGlobalOptions({maxInstances: 10})

and this inside my firebase.json:

  "frameworksBackend": {
    "region": "us-central1",
    "maxInstances": 10
  }
like image 752
Chris Avatar asked Sep 18 '25 21:09

Chris


1 Answers

I got it working. I had smaller issues in my code, like Typos, or the suggested improvements from the answers.

By following this Sample-Code and also looking into doc for sendEachForMultiCast and onDocumentCreated I was able to make it work with this code:

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const { onDocumentCreated } = require("firebase-functions/v2/firestore");
const { setGlobalOptions } = require("firebase-functions/v2");

admin.initializeApp();


// Set the maximum instances to 10 for all functions
setGlobalOptions({ maxInstances: 10 });

const notificationPath = "allUsers/{userId}/notifications/{notificationId}";
exports.sendNotification = onDocumentCreated(notificationPath, async (event) => {
    functions.logger.log("New notificatin document was created");

    const snapshot = event.data;
    if (!snapshot) {
        console.log("No data associated with the event");
        return;
    }
    const data = snapshot.data();

    // access a particular field as you would any JS property
    const name = data.name;
    const senderUid = data.senderUid;
    const receiverUid = data.receiverUid;
    const notificationOption = data.option;

    if (notificationOption === "recievedFriendRequest") {
        await onSentFriendRequest(senderUid, receiverUid);
    } else {
        functions.logger.log(`is notificationOption: ${notificationOption}`);

    }
});

async function onSentFriendRequest(ownerId, userId) {
    // Get the owners details
    const owner = await admin.firestore().collection("allUsers").doc(ownerId).get();

    // Get the users details
    const user = await admin.firestore().collection("allUsers").doc(userId).get();

    const userHasNotificationsEnabled = user.data().isPushEnabled;

    if (!userHasNotificationsEnabled) {
        functions.logger.log("User does not have push enabled");
        return;
    }
 

    // Listing all tokens as an array.
    tokens = user.data().messagingTokens;

    // Send message to all tokens
    const response = await admin.messaging().sendEachForMulticast({
        tokens: tokens,
        notification: {
            title: "Neue Freundschaftsanfrage",
            body: `${owner.data().username} möchte mit dir befreundet sein.`,
        },
        data: {
            ownerId: ownerId,
            userId: userId,
            notificationOption: "receivedFriendRequest",
        },
    });

    functions.logger.log("Successflully send Notification");


    // For each message check if there was an error.
    const tokensToRemove = [];
    response.responses.forEach((result, index) => {
        const error = result.error;
        if (error) {
            functions.logger.error(
                'Failure sending notification to',
                tokens[index],
                error
            );
            // Cleanup the tokens who are not registered anymore.
            if (error.code === 'messaging/unregistered' || 
                error.code === 'messaging/invalid-argument') {               
                tokensToRemove.push(admin.firestore().collection("allUsers").doc(userId).update({
                    "messagingTokens": admin.firestore.FieldValue.arrayRemove(tokens[index])
                }));
            }
        }
    });
    return Promise.all(tokensToRemove);
}
like image 60
Chris Avatar answered Sep 20 '25 11:09

Chris