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:
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
}
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With