I'm working with Firebase notifications using node.js.
After compile, when I'm sending request to other user of app (request makes notification), firebase log shows error:
TypeError: Cannot read property 'receiver_id' of undefined
at exports.sendNotification.functions.database.ref.onWrite.event (/user_code/index.js:12:36)
at Object. (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:112:27)
at next (native)
at /user_code/node_modules/firebase-functions/lib/cloud-functions.js:28:71
at __awaiter (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:24:12)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:82:36)
at /var/tmp/worker/worker.js:700:26
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
Index.js code:
'use strict'
const functions = require('firebase-functions');
const admin = require ('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification =
functions.database.ref('/Notifications/{receiver_id}/{notification_id}')
.onWrite(event =>
{
const receiver_id = event.params.receiver_id;
const notification_id = event.params.notification_id;
console.log('We have a notification to send to :', receiver_id);
if(!event.data.val())
{
return console.log('A notification has been deleted from the database: ', notification_id);
}
const deviceToken = admin.database().ref(`/Users/${receiver_id}/device_token`).once('value');
return deviceToken.then(result =>
{
const token_id = result.val();
const payload =
{
notification:
{
title: "Friend Request",
body: "you have received a new friend request",
icon: "default"
}
};
return admin.messaging().sendToDevice(token_id, payload)
.then(response =>
{
console.log('This was the notification feature.');
});
});
});
I have read about new APIs on site:
https://firebase.google.com/docs/functions/beta-v1-diff
I think I must change event to context, but I don't know how.
Is anybody know what's the issue?
Thank's for any Help :)
The Firebase documentation on the new data and context shows where the params now live:
The context parameter provides information about the function's execution. Identical across asynchronous functions types, context contains the fields eventId, timestamp, eventType, resource, and params.
So to get rid of that error, you'll need to change the first bit of your function to:
exports.sendNotification =
functions.database.ref('/Notifications/{receiver_id}/{notification_id}')
.onWrite((data, context) =>
{
const receiver_id = context.params.receiver_id;
const notification_id = context.params.notification_id;
...
There are more, similar changes that you'll need to make. If you're having a hard time making those yourself, I recommend you check back in with where you got the code from.
Related
Bear with me. I've spent a month just PHRASING this question: I've been using Firebase Database and Firebase functions for about a year. I've gotten it to work... but only if I sent the text of the message as a STRING. The problem is that now I wish to receive an OBJECT instead but I'm unsure of how to do this in FireBaseMessage.
My previous structure:
messages
T9Vh5cvUcbqC8IEZowBpJC3
ZWfn7876876ZGJeSNBbCpPmkm1
message
"messages": {
".read": true,
"$receiverUid": {
"$senderUid": {
"$message": {
".read": true,
".write": "auth.uid === $senderUid"
And my function for the listener was this:
exports.sendMessage = functions.database.ref('/messages/{receiverUid}/{senderUid}/{message}')
This is problematic... for a variety of reasons. Namely if the old message was "Hey" and then that same person just writes "Hey" again... then the original gets overwritten.
So my NEW structure is more like this:
messages
-LkVcYqJoEroWpkXZnqr
body: "genius grant"
createdat: 1563915599253
name: "hatemustdie"
receiverUid: "TW8289372984KJjkhdsjkhad"
senderUid: "yBNbs9823789KJkjahsdjkas"
Which is written as:
mDatabase.child("messages").push().setValue(message);
...and I'm just unsure about how to write out that function.
I mean... IDEALLY... it would be something like:
exports.sendMessage = functions.database.ref('/messages/{receiverUid}/{senderUid}/{msgID}/{msgOBJECT}')
...but I'm just not sure how Firebase functions is reading this new structure.
Now I'm pushing to the database like so:
mDatabase.child("messages").child(guid).child(user_Id).push().setValue(msgObject).addOnSuccessListener(this, new OnSuccessListener<Void>() {
#Override
public void onSuccess(#NonNull Void T) {
Log.d("MessageActivity", "Message Sent");
Basically I would just like to receive the message object... with everything in it... when it arrives from the notification... and be able to easily parse the body, date, userids, etc.
Can someone explain the correct way to go about this?
UPATE By request here's the complete cloud function:
exports.sendMessage = functions.database.ref('/messages/{receiverUid}/{senderUid}/{msgId}/{message}')
.onWrite(async (change, context) => {
const message = context.params.message;
// const messageId = context.params.messageId;
const receiverUid = context.params.receiverUid;
const senderUid = context.params.senderUid;
// If un-follow we exit the function.
if (!change.after.val()) {
return console.log('Sender ', senderUid, 'receiver ', receiverUid, 'message ', message);
}
console.log('We have a new message: ', message, 'for: ', receiverUid);
// Get the list of device notification tokens.
const getDeviceTokensPromise = admin.database()
.ref(`/users/${receiverUid}/notificationTokens`).once('value');
// Get the follower profile.
const getSenderProfilePromise = admin.auth().getUser(senderUid);
// The snapshot to the user's tokens.
let tokensSnapshot;
// The array containing all the user's tokens.
let tokens;
const results = await Promise.all([getDeviceTokensPromise, getSenderProfilePromise]);
tokensSnapshot = results[0];
const sender = results[1];
// Check if there are any device tokens.
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no notification tokens to send to.');
}
console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
console.log('Fetched sender profile', sender);
// console.log('David you're looking for the following UID:', followerUid);
// Notification details.
const payload = {
notification: {
title: `${sender.displayName} sent you a message.`,
body: message,
tag: senderUid
},
// 'data': { 'fuid': followerUid }
data: {
type: 'message',
name: sender.displayName
}
};
console.log('David you are looking for the following message:', message);
// Listing all tokens as an array.
tokens = Object.keys(tokensSnapshot.val());
// Send notifications to all tokens.
const response = await admin.messaging().sendToDevice(tokens, payload);
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.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);
});
Since you now store the sender and receiver's UIDs inside the message, the declaration of your Cloud Function will need to change.
Instead of this:
exports.sendMessage = functions.database.ref('/messages/{receiverUid}/{senderUid}/{msgId}/{message}').onWrite(async (change, context) => {
You'll need to trigger on:
exports.sendMessage = functions.database.ref('/messages/{messageId}').onWrite(async (change, context) => {
So with this change your code will trigger on each message that is written /messages.
Now you "just" need to get the sender and receiver's UID. And since you no longer can get them from the context, you will instead get them from the change. Specifically change.after contains the data snapshot as it exists in the database after the write has completed. So (as long as you're not deleting the data), you can get the UIDs with:
const receiverUid = change.after.val().receiverUid;
const senderUid = change.after.val().senderUid;
And you'll also get the actual message from there of course:
const message = change.after.val().message;
And just in case you need the message ID (the -L... key that it was written under in the database):
const messageId = change.after.val().messageId;
You need a trigger on just the messageId:
exports.sendMessage = functions.database.ref('/messages/{messageId}').onWrite((change, context) => {
const changedData = change.after.val(); // This will have the complete changed data
const message = change.after.val().message; // This will contain the message value
......
});
Elaborating on Frank's answer:
You can't get the data from context like const message = context.params.message;because those parameters don't exists anymore on the context.
I'm trying to do a simple notification function
but every time i fire the function i get ERROR
TypeError: Cannot read property 'params' of undefined
at exports.sendNotification.functions.database.ref.onWrite (/user_code/index.js:23:32)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:105:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:135:20)
at /var/tmp/worker/worker.js:758:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
Or i get the error
TypeError: Cannot read property 'user_id' of undefined
I got an answer from here
but i't didn't help at all , and i can't find the problem . this is my code
'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.database.ref('/notifications/{user_id}/{notification_id}').onWrite((change,context) => {
const user_id = event.params.user_id;
const notification_id = event.params.notification_id;
console.log('We have a notification from : ', user_id);
if(!context.data.val()){
return console.log('A Notification has been deleted from the database : ',
notification_id);
}
const fromUser =admin.database().ref(`/notifications/${user_id}/${notification_id}`).once('value');
return fromUser.then(fromUserResult => {
const from_user_id = fromUserResult.val().from;
console.log('You have new notification from : ', from_user_id);
const userQuery = admin.database().ref(`Users/${from_user_id}/name`).once('value');
const deviceToken = admin.database().ref(`/Users/${user_id}/device_token`).once('value');
return Promise.all([userQuery, deviceToken]).then(result => {
const userName = result[0].val();
const token_id = result[1].val();
const payload = {
notification: {
title : "New Friend Request",
body: `${userName} has sent you request`,
icon: "default",
click_action : "none"
},
data : {
from_user_id : from_user_id
}
};
return admin.messaging().sendToDevice(token_id, payload).then(response => {
return console.log('This was the notification Feature');
});
});
});
});
You never defined event, so it's undefined. You're trying to access a property on an undefined variable. Did you mean context.params.user_id?
(You're probably using an out of date tutorial. I see bad "sendNotification" functions like this all the time on Stack Overflow. Let the author know.)
This question already has answers here:
Firebase functions how to send a notification in Android
(1 answer)
Firebase functions: cannot read property 'user_id' of undefined
(1 answer)
Firebase cloud functions stopped working - event.data undefined
(2 answers)
node js function onWrite is not working properly in google cloud function
(1 answer)
Closed 4 years ago.
I'm working with Notifications but the Notification is not working and getting this error, I am new to this so i can't fully understand this and getting tilted by the error. Any help would be appreciated, I don't find any related solutions about this
ReferenceError: event is not defined
at exports.sendNotification.functions.database.ref.onWrite (/user_code/index.js:9:31)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:105:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:135:20)
at /var/tmp/worker/worker.js:744:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
and Here is my index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification =
functions.database.ref('/notifications/{user_id}/{notification_id}')
.onWrite((change, context) => {
const user_id = event.params.user_id;
const notification = event.params.notification;
console.log('We have a notification to send to: ', user_id);
if(!event.data.val())
{
return console.log('A Notification has been deleted from database: ', notification_id);
}
const fromUser = admin.database().ref(`/notifications/${user_id}/${notification_id}`);
return fromUser.then(fromUserResult => {
const from_user_id = fromUserResult.val().from;
console.log('You have new Notification from: ', from_user_id);
const userQuery = admin.database().ref(`Users/${from_user_id}/name`).once('value');
const deviceToken = admin.database().ref(`/Users/${user_id}/device_token`).once('value');
return Promise.all([userQuery, deviceToken]).then(result => {
const userName = result[0].val();
const token_id = result[1].val();
const payload = {
notification: {
title: "Message Request",
body: `${userName} has sent you a Message Request`,
icon: "logo.png",
click_action: "com.example.gab.quadrantms_TARGET_NOTIFICATION"
},
data : {
from_user_id : from_user_id
}
};
return admin.messaging().sendtoDevice(token_id, payload).then(response =>{
console.log('This was the Notification Feature');
return true;
});
});
});
});
Just as the error says, event isn't defined anywhere. It looks like you should be using context instead.
const user_id = context.params.user_id;
const notification = context.params.notification;
Here are the docs for EventContext: https://firebase.google.com/docs/reference/functions/functions.EventContext
And RefBuilder.onWrite: https://firebase.google.com/docs/reference/functions/functions.database.RefBuilder#onWrite
I'm trying to implement push notification using firebase in my project but not being able to do so.Below is my index.js file, i have very little knowledge about javascript and nodejs and thats why not being able to figure out the problem.
'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.database.ref('/Notifications/{receiver_id}/{notification_id}').onWrite((data,context) =>
{
const receiver_id = context.params.receiver_id;
const notification_id = context.params.notification_id;
console.log('We have new notification to send to : ', receiver_id);
/*if(!context.data.val()){
return console.log('A notification has been deleted from the databse : ', notification_id);
}*/
const deviceToken = admin.database().ref(`Users/${receiver_id}/device_token`).once('value');
return deviceToken.then(result => {
const token_id = result.val();
const payload = {
notification: {
title : "Friend Request",
body : "You've received a new Friend Request",
icon : "default"
}
};
return admin.messaging().sendToDevice(token_id,payload).then(response => {
console.log('This was the notification feature');
return true;
});
});
});
Can anyone please explain me this code and help out with my problem.
Every device has a different token. Seems you are storing only one token for one user. That's why you can send the notification to only one device. If you want to send it to multiple devices you have to store multiple device tokens and send the notification to all those devices.
I have an android Client Application and and Admin Application using Firebase. Whenever a user registers in Client Application, I need to send a push notification to Admin app. I am trying to use Cloud Functions for Firebase. I have exported the function, and i can see that on firebase console as well.
This is my index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendMessageToAdmin = functions.database.ref('/tokens/users/{userId}/{regToken}').onWrite(event => {
if (event.data.previous.exists()) {
return;
}
const userId = event.params.userId;
const regToken = event.params.regToken;
// Notification details.
const payload = {
notification: {
title: 'You have a new User.',
body: `${userId} is the id.`,
}
};
return admin.messaging().sendToDevice(regToken, payload);
});
Here is my database structure at firebase :
If i use any online portal to send push or even FCM to send push to admin app for testing purpose, i am receiving the push. But this Cloud Function is not sending the push. Can someone guide me whats wrong i am doing.
EDIT
If i change the function to the following , then it works. But i am still wondering why the above function didn't work.
exports.sendMessageToAdmin = functions.database.ref('/tokens/users/{userId}').onWrite(event => {
if (event.data.previous.exists()) {
return;
}
const userId = event.params.userId;
var eventSnapshot = event.data;
const regToken = eventSnapshot.child("regToken").val();
Notification details.
const payload = {
notification: {
title: 'You have a new User.',
body: `${userId} is the id.`,
}
};
return admin.messaging().sendToDevice(regToken, payload);
});
In your original code, you have:
const regToken = event.params.regToken;
event.params.regToken does not return the value of regToken it returns the value of the wildcard path segment in your reference.