Realtime database function triggers constantly - node.js

I have deployed a JS function for Firebase realtime database triggers. In its operations, it should send a push notification just on value update in the database, which is dead simple:
{
"rollo" : "yes"
}
If value changes to yes it should trigger notification. If it goes to "no" then it should do nothing. Here is the JS function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNewPostNotif = functions.database.ref('/rollo').onUpdate((change, context) => {
console.log('Push notification event triggered');
const beforeData = change.before.val();
const payload = {
notification: {
title: 'Push triggered!',
body: "Push text",
sound: "default"
}
};
const options = {
priority: "high",
timeToLive: 60 * 10 * 1
};
return admin.messaging().sendToTopic("notifications", payload, options);
});
Also even though I have set TTL, each value change sends another push notification.
Any ideas?

I would try something like this:
exports.sendNewPostNotif = functions.database.ref('/rollo').onWrite((change, context) => {
const newData = change.after.val();
const oldData = change.before.val();
const payload = {
notification: {
title: 'Push triggered!',
body: "Push text",
sound: "default"
}
};
const options = {
priority: "high",
timeToLive: 60 * 10 * 1
};
if (newData != oldData && newData == 'yes') {
return admin.messaging().sendToTopic("notifications", payload, options);
}
});

onUpdate():
triggers when data is updated in the Realtime Database.
When you update it to "no" it will send a notification and when you update it to "yes" it will also send a notification.
https://firebase.google.com/docs/functions/database-events

Related

Firebase cloud function doesn't send push notification with async

My goal is to send a push notification when a user sends a message. I am trying to do this by retrieving all of the push tokens from the firestore database, and sending a multicast message using these tokens each time a new message is added to the realtime database.
Works
This first example works. There is no token retrieval, the tokens are hardcoded. I do receive the notifications.
exports.notifyUsers = functions.database.ref('/messages/{messageId}').onCreate((liveSnapshot, context) => {
const name = context.params.messageId;
const message = liveSnapshot.val().toString();
const tokens = [
"e6erA_qM...",
"ePU9p_CI...",
];
const payload = {
notification: {
title: `New message from ${name}`,
body: message,
badge: '1',
sound: 'default'
},
tokens: tokens,
}
const res = admin.messaging().sendMulticast(payload);
console.log(`response: ${res}`);
Doesn't work
This doesn't work, I don't receive any notifications.
exports.notifyUsers = functions.database.ref('/messages/{messageId}').onCreate(async (liveSnapshot, context) => {
const name = context.params.messageId;
const message = liveSnapshot.val().toString();
const snapshot = await admin.firestore().collection('users').get();
const tokens = snapshot.docs.map(doc => doc.data().token);
const payload = {
notification: {
title: `New message from ${name}`,
body: message,
badge: '1',
sound: 'default'
},
tokens: tokens,
}
const res = await admin.messaging().sendMulticast(payload);
console.log(`response: ${res}`);
I have verified that the tokens retrieved from the database are the same as the hardcoded ones with the following code.
exports.notifyUsers = functions.database.ref('/messages/{messageId}').onCreate(async (liveSnapshot, context) => {
const hardcodedTokens = [
"e6erA_qM...",
"ePU9p_CI...",
];
const snapshot = await admin.firestore().collection('users').get();
const tokens = snapshot.docs.map(doc => doc.data().token);
let same = true;
hardcodedTokens.forEach(el => {
if (!tokens.includes(el)) {
same = false;
}
});
console.log(same);
})
This logs true in the firebase cloud functions console.
The function uses Node 12.
I experienced a similar problem recently, and solved it by breaking out Android and iOS specific fields according to the Firebase docs :
const message = {
"notification": {
"title": `New message from ${name}`,
"body": message,
},
'apns': {
'payload': {
'aps': {
'badge': 1,
},
},
},
'android':{
'notification':{
'notificationCount': 1,
},
},
"tokens": tokens,
}
The following code works.
async function getTokens() {
const snapshot = await admin.firestore().collection('users').get();
return snapshot.docs.map(doc => doc.data().token);
}
exports.notifyUsers = functions.database.ref('/messages/{messageId}').onCreate(async (snapshot, context) => {
const name = context.params.messageId;
const message = snapshot.val().toString();
const tokens = await getTokens();
const payload = {
notification: {
title: `New message from ${name}`,
body: message,
},
tokens: tokens,
};
await admin.messaging().sendMulticast(payload);
})
I logged my response like below:
const res = await admin.messaging().sendMulticast(payload);
console.log('response:', JSON.stringify(res));
This logged the following:
response: {"responses":[{"success":false,"error":{"code":"messaging/invalid-argument","message":"Invalid JSON payload received. Unknown name \"sound\" at 'message.notification': Cannot find field."}},{"success":false,"error":{"code":"messaging/invalid-argument","message":"Invalid JSON payload received. Unknown name \"sound\" at 'message.notification': Cannot find field."}}],"successCount":0,"failureCount":2}
Based on this, I believe the problem was the sound argument in the notification part of the payload. It works after removing it.

firebase functions showing error cannot read property previous of undefined

I had implemented firebase functions in my app and previously it was working fine but now it is showing error Cannot read property 'previous' of undefined
Error Logs of function
TypeError: Cannot read property 'previous' of undefined
at exports.LoveNotification.functions.database.ref.onWrite (/user_code/index.js:223:16)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:109:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:139:20)
at /var/tmp/worker/worker.js:730:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
The signature of Cloud Functions triggers has changed. You seem to be using beta, but are deploying to the latest version. See the migration guide for complete instructions.
From there:
Before (<= v0.9.1)
exports.dbWrite = functions.database.ref('/path').onWrite((event) => {
const beforeData = event.data.previous.val(); // data before the write
const afterData = event.data.val(); // data after the write
});
Now (>= v1.0.0)
exports.dbWrite = functions.database.ref('/path').onWrite((change, context) => {
const beforeData = change.before.val(); // data before the write
const afterData = change.after.val(); // data after the write
});
So your code should look something like this:
exports.LoveNotification = functions.database.ref("/Member/{pushId}").onWrite((change, context) => {
if (change.before.exists()) {
return;
} else {
var eventLove = change.after.data.val();
var author =eventLove.fullname;
var title = eventLove.course;
var key = eventLove.key;
const payload = {
"data": {
"post_id": key
},
notification: {
title: author +'Joined the app',
body: `Course `+title,
sound: "default",
icon: "ic_launcher",
}
};
const options = {
priority: "high",
timeToLive: 60 * 60 * 24 //24 hours
};
console.log('Sending notifications');
return admin.messaging().sendToTopic("Member", payload, options);
}
});

Node Js value not showing in notification when testing

I am making a notification using firebase cloud functions with node js and my app made on swift
this is my payload
var payload = {
notification: {
title: (goOfflineTimePeriod,"Inactive for minutes you are now offline"),
body: "Time period for inactive log off can be changed in your settings"
though my notification my notification only shows as; "Inactive for minutes you are now offline", "Time period for inactive log off can be changed in your settings"
so the variable; goOfflineTimePeriod does not show in the notification
I am only new to node js is there a reason why "goOfflineTimePeriod" does not show in the notification?
here is my full node js function code;
exports.goOfflineAlert = functions.firestore
.document('/goneOffline/{uid}')
.onCreate((snap, context) => {
var db = admin.firestore();
var uid = context.params.uid;
const newValue = snap.data();
const goOfflineTimePeriod = newValue.goneOffline;
console.log('uid is',uid)
var cityRef = db.collection('Users').doc(uid);
var getDoc = cityRef.get()
.then(doc => {
if (!doc.exists) {
return console.log('No such document!');
} else {
const newValue = doc.data();
const age = newValue.Age;
const name = newValue['Display Name'];
const fcmToken = newValue.fcmToken;
const goOfflineTimePeriod = newValue.goOfflineTimePeriod;
console.log('Document data:', doc.data(),age,fcmToken,name,goOfflineTimePeriod);
var payload = {
notification: {
title: (goOfflineTimePeriod,"Inactive for minutes you are now offline"),
body: "Time period for inactive log off can be changed in your settings"
}
}
A , operator does not concatenate strings in JavaScript, but it returns the second operand. Instead you should use + or template string. For example:
title: goOfflineTimePeriod+" Inactive for minutes you are now offline",

How to get the key of a child based of the object in Firebase

I was wondering if there is a way to retrieve the _random number in firebase using node.js and encapsulate it in my notifications body section.? I tried to create an array and read everything from firebase into the array but it didn't help
exports.sendFigureNotification = functions.database.ref('_random').onWrite(event => {
var rootRef = admin.database().ref();
rootRef.once("value", function(snapshot) {
});
const payload = {
notification: {
title: 'Title',
body: 'The Cloud Function works', //use _random to get figure at index key
badge: '1',
sound: 'default'
}
};
const options = {
priority:"high",
timeToLive: 60 * 60 * 24, //24 hours
content_available: true
};
const topic = "HBF"
console.log('Sending notifications');
return admin.messaging().sendToTopic(topic, payload, options);
});
https://i.stack.imgur.com/t22Ou.png

Get "Undefined" for snapshot values

log result
inside of the log error
I am currently in the process of setting up my Firebase Cloud functions to have a user to user push notification everytime there is a new child added to "Messages". For each user, there is a notification stored in a node in this structure "/User/UID/Token". However, in my logs in the Firebase console it turns up that values being returned is "Undefined". This is my first time working with Node.js so everything is very new. Any help would be appreciated. Here is what is inside of function
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
// Listens for new messages added to messages/:pushId
exports.messageWritten = functions.database.ref('/messages/{pushId}').onWrite( event => {
console.log('Push notification event triggered');
// Grab the current value of what was written to the Realtime Database.
var valueObject = event.data.val();
console.log(valueObject.text,valueObject.toId);
return admin.database().ref(`/Users/${valueObject.toId}`).once('value').then(snapshot =>{
console.log('the users name',snapshot.name)
console.log('the users token',snapshot.token)
})
// Create a notification
const payload = {
notification: {
title:snapshot.name +' sent you a message',
body: valueObject.text,
sound: "default"
},
};
//Create an options object that contains the time to live for the notification and the priority
const options = {
priority: "high",
timeToLive: 60 * 60 * 24
};
return admin.messaging().sendToDevice(snapshot.token, payload, options);
});
You have two return statements in your function. The code after the first return statement (which sends the message) won't be run.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
// Listens for new messages added to messages/:pushId
exports.messageWritten = functions.database.ref('/messages/{pushId}').onWrite(event => {
console.log('Push notification event triggered');
// Grab the current value of what was written to the Realtime Database.
var valueObject = event.data.val();
console.log(valueObject.text, valueObject.toId);
return admin.database().ref(`/Users/${valueObject.toId}`).once('value').then(snapshot => {
console.log('the users name', snapshot.val().name)
console.log('the users token', snapshot.val().token)
// Create a notification
const payload = {
notification: {
title: snapshot.val().name + ' sent you a message',
body: valueObject.text,
sound: "default"
},
};
//Create an options object that contains the time to live for the notification and the priority
const options = {
priority: "high",
timeToLive: 60 * 60 * 24
};
return admin.messaging().sendToDevice(snapshot.val().token, payload, options);
})
});

Resources