cloud functions returning null for dataSnapshot - javascript

I am using cloud notifications for sending notifications whenever some data is updated in the realtime database, and I am sending the notificaations with some details which are also from the database
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.notifyUsers = functions.database.ref('/').onUpdate(event => {
var message = event.data.val();
admin.database().ref('users/'+message.uid).on('value', function(dataSnapshot) {
var usernameOfSender = dataSnapshot.child('username').val();
console.log('message: '+message.val());
console.log('dataSnapshot.val: '+dataSnapshot.val());
console.log('usernameOfSender: '+usernameOfSender);
// Notification details.
const text = message.message;
const payload = {
notification: {
title: `${usernameOfSender} posted ${text ? 'a message' : 'an image'}`,
body: text ? (text.length <= 100 ? text : text.substring(0, 97) + '...') : '',
icon: dataSnapshot.child('profilePic').val() || '/images/defaultProfilePic.png',
click_action: `https://${functions.config().firebase.authDomain}`
}
};
// Get the list of device tokens.
return admin.database().ref('fcmTokens').once('value').then(allTokens => {
if (allTokens.val()) {
// Listing all tokens.
const tokens = Object.keys(allTokens.val());
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// 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(allTokens.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
}
});
});
});
When I check my firebase console, this is what I get:
usernameOfSender: null
dataSnapshot.val: null
message: [object Object]
and the notification comes as null posted an image, with the default profile picture.

Related

error firebase functions [Promises must be handled appropriately] on deploy

I was written a code previous week and it deploys without any error on firebase server. but now I cannot deploy it again on another account in orders to I don't change my code!
one of my friends tell me this in about new update of firebase but I don't find any solution for this!
it shows these errors
Promises must be handled appropriately
and
block is empty
the first error pointed to my first line and the second one pointed to end 'catch' block :
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();
// export const helloWorld = functions.https.onRequest((request, response) => {
// console.log("sadegh");
// response.send("Hello from Firebase1!");
// });
//
export const sendChatNotification = functions
.firestore.document('rooms/{roomId}/messages/{messageId}')
.onCreate((snap, context) => {
const roomId = context.params.roomId;
const messageId = context.params.messageId;
const newValue = snap.data();
const receiverId = newValue.receiverId;
const text = newValue.text;
const type = newValue.type;
const senderName = newValue.senderName;
var p = admin.firestore().collection("users").doc(receiverId).get();
p.then(snapshot2 => {
const data2 = snapshot2.data();
const firebaseNotificationToken = data2.firebaseNotificationToken;
// const name = data2.name;
if (type == 'voiceCall' || type == 'videoCall' || type == 'hangUp') {
const channelId = newValue.channelId;
const senderId = newValue.senderId;
const status = newValue.status;
console.log("type: " + type + " /status: " + status)
let message = {
data: {
type: type,
senderId: senderId,
senderName: senderName,
receiverId: receiverId,
status: status,
channelId: channelId,
roomId: roomId
},
token: firebaseNotificationToken
};
sendMessage(message)
if (status == "canceled") {
let message1 = {
notification: {
title: '☎ Missed voice call ',
body: senderName
},
token: firebaseNotificationToken
};
sendMessage(message1)
} else if ((type == 'voiceCall' || type == 'videoCall') && status = '') {
let message1 = {
notification: {
title: '☎ ' + senderName + ' is calling you',
body: 'tap to answer...'
},
token: firebaseNotificationToken
};
sendMessage(message1)
}
} else {
let message = {
notification: {
title: '📃 ' + senderName,
body: text
},
token: firebaseNotificationToken
};
sendMessage(message)
}
return "";
}).catch((e) => {
console.log('error: ' + e);
return null;
});
// return "";
// }).catch(e=>{console.log('error: '+e)});
return "sadegh";
});
function sendMessage(message) {
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
}
Your code is a bit messy and it is not really easy to understand it without dedicating a long time.
However, here is below a piece of code that should work and that cover one case of your Business Logic. Note how the promises returned by the asynchronous tasks are returned.
export const sendChatNotification = functions.firestore
.document('rooms/{roomId}/messages/{messageId}')
.onCreate((snap, context) => {
const roomId = context.params.roomId;
const messageId = context.params.messageId;
const newValue = snap.data();
const receiverId = newValue.receiverId;
const text = newValue.text;
const type = newValue.type;
const senderName = newValue.senderName;
var p = admin
.firestore()
.collection('users')
.doc(receiverId)
.get();
return p.then(snapshot2 => { // <- HERE, the promise is returned
const data2 = snapshot2.data();
const firebaseNotificationToken = data2.firebaseNotificationToken;
if (type == 'voiceCall' || type == 'videoCall' || type == 'hangUp') {
const channelId = newValue.channelId;
const senderId = newValue.senderId;
const status = newValue.status;
console.log('type: ' + type + ' /status: ' + status);
let message = {
data: {
type: type,
senderId: senderId,
senderName: senderName,
receiverId: receiverId,
status: status,
channelId: channelId,
roomId: roomId
},
token: firebaseNotificationToken
};
return admin.messaging().send(message); // <- HERE, the promise is returned
}
});
});
I would suggest you watch the 3 videos about "JavaScript Promises" from the Firebase video series: https://firebase.google.com/docs/functions/video-series/
The problem is you commented the return in your catch block
As your Firebase .get() function must return a promise, in your code, if it fails, it won't return a promise and it will hang there.
either use return null or return something to be handled by the calling app

Firebase cloud messaging Each then() should return a value or throw promise/always-return

I am writing a cloud function for firebase for my android app. I can't resolve this error. I am a complete newbie.
29:73 error Each then() should return a value or throw promise/always-return
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/comment')
.onWrite((change, context) => {
// get user ids
const reciever_id = context.params.reciever_id;
const sender_id = context.params.sender_id;
const comment = context.params.comment;
const object_id = context.params.object_id;
const objecttype = context.params.objecttype;
//get the token of reciever
return admin.database().ref("/users/" + reciever_id).once('value').then(snap => {
const token = snap.child("token").val();
// Create a payload
var payload = {
data: {
data_type: "direct_message",
title: "Comment from" + sender_id,
comment: comment,
object_id: object_id,
objecttype: objecttype,
}
};
// Sent To device with token Id : THIS IS LINE 29
return admin.messaging().sendToDevice(token, payload).then(response => {
console.log("Successfully sent message:", response);})
.catch(error => {console.log("Error:", error); });
}); // token
}); // onWrite
IT worked I just changed this
// Sent To device with token Id
return admin.messaging().sendToDevice(token, payload).then(result => {
return console.log("Successfully sent message:", result);
})

Firebase Push Notification to different group of tokens

I would like to send notification to different token groups.
My RealTime Database look like this
fcm-token
HHE Data
(Token)
HHE Other
(Token)
this code only work with one of the fcm-token groups.
enter code heregconst functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.notification= functions.database.ref('notification/{id}').onWrite(evt => {
const payload = {
notification:{
title : 'Ny person på listen',
body : '',
badge : '1',
sound : 'default'
}
};
return admin.database().ref('fcm-token/HHE Data').once('value').then(allToken => {
if(allToken.val()){
console.log('token available');
const token = Object.keys(allToken.val());
return admin.messaging().sendToDevice(token,payload);
}else{
console.log('No token available');
}
});
});
How do I get what the {id} is?
the Path "notification/{id}" is specific outside of the code
image
but I would like to use it like this:
return admin.database().ref('fcm-token/' + id).once('value').then(allToken => {
if(allToken.val()){
console.log('token available');
const token = Object.keys(allToken.val());
return admin.messaging().sendToDevice(token,payload);
}else{
console.log('No token available');
}
});
The only solution I have come up with is to do it manually for each group.
and create function for each, because path it check is specific outside of the code. image
like this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.notification = functions.database.ref('notification/HHE Data/{id}').onCreate(evt => {
const payload = {
notification:{
title : 'Ny person på listen',
body : '',
badge : '1',
sound : 'default'
}
};
return admin.database().ref('fcm-token/HHE Data').once('value').then(allToken => {
if(allToken.val()){
console.log('token available');
const token = Object.keys(allToken.val());
return admin.messaging().sendToDevice(token,payload);
}else{
console.log('No token available');
}
});
return admin.database().ref('notification').once('value');
});

How can I get different types of notification?

I don't know how to send different types of notification to the device from Firebase cloud function in index.js I want to send (comments notification)(like notification).
I am using this code to get following notification to device but I don't know how to get other.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/notification/{user_id}/{notification_id}').onWrite((change, context) => {
const user_id = context.params.user_id;
const notification_id = context.params.notification_id;
console.log('We have a notification to send to : ', user_id);
const fromUser = admin.database().ref(`/notification/${user_id}/${notification_id}`).once('value');
return fromUser.then(fromUserResult => {
const from_user_id = fromUserResult.val().from;
const from_message = fromUserResult.val().message;
console.log('You have new notification from : ', from_user_id);
const userQuery = admin.database().ref(`users/${from_user_id}/username`).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 payload1 = {
notification:{
title: "some is following you",
body: `${userName} is following you`,
icon: "default",
click_action : "alpha.noname_TARGET_NOTFICATION"
},
data:{
from_user_id:from_user_id
}
};
return admin.messaging().sendToDevice(token_id, payload1).then(result=>{
console.log("notification sent");
});
})
.then(response => {
console.log('This was the notification Feature');
return true;
}).catch(error => {
console.log(error);
//response.status(500).send(error);
//any other error treatment
});
});
});
You can change what you are sending to the /notification/${user_id}/${notification_id} node to include fields that will let you identify and create different notifications in the cloud function.
For example, you could add a type field and then:
return fromUser.then(fromUserResult => {
const from_user_id = fromUserResult.val().from;
const from_message = fromUserResult.val().message;
const from_type = fromUserResult.val().type;
Then you could build your notification based on type:
if(from_type === NOTIFICATION_FOLLOW){
payload1 = {
notification:{
title: "some is following you",
body: `${userName} is following you`,
icon: "default",
click_action : "alpha.noname_TARGET_NOTFICATION"
},
data:{
from_user_id:from_user_id
}
};
}else{
//set payload1 for a different notification
}
Add whatever fields are necessary for your payload and extend the control structure as needed.

Firebase TypeError: Cannot read property 'val' of undefined

I have tried Firebase cloud function for sending a notification.My project structure
and this is the index.js,
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.pushNotification = functions.database.ref('/messages').onWrite( event => {
console.log('Push notification event triggered');
const message = event.data.val();
const user = event.data.val();
console.log(message);
console.log(user);
const topic = "myTopic";
const payload = {
"data": {
"title": "New Message from " + user,
"detail":message,
}
};
return admin.messaging().sendToTopic(topic, payload);
});
The above code is misconfigured, when I deploy in Node.js, LOG in Function shows:
"TypeError: Cannot read property 'val' of undefined".
What Actually I am trying to do :
I am trying to extract info from snapshot load into that index.js so that when a new child gets added to Real-time database, it should trigger a notification payload with a title and body.
In Android, I use a child listener, for listening when a new record is added
FirebaseDatabase.getInstance().getReference().child("messages")
OnChildAdded(.....){
if (dataSnapshot != null) {
MessageModel messageModel = dataSnapshot.getValue(MessageModel.class);
if (messageModel != null) {
// do whatever
}
}
But in index.js, I could not able to parse that.
A bit guidance how to fixate index.js according to my database structure would be immensely appreciated.
PS- I have never done coding in JS
If you want more context, I'd be happy to provide it.
Change this:
exports.pushNotification = functions.database.ref('/messages').onWrite( event => {
const message = event.data.val();
const user = event.data.val();
});
to this:
exports.pushNotification = functions.database.ref('/messages').onWrite(( change,context) => {
const message = change.after.val();
});
Please check this:
https://firebase.google.com/docs/functions/beta-v1-diff#realtime-database
The cloud functions were changed and now onWrite has two parameters change and context
The change has two properties before and after and each of these is a DataSnapshot with the methods listed here:
https://firebase.google.com/docs/reference/admin/node/admin.database.DataSnapshot
'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/NOTIFICATIONS/{UserId}/{{notification_id}').onWrite((change, context) =>
{
const UserId = context.params.UserId;
const notification = context.params.notification;
console.log('The user Id is : ', UserId);
if(!change.after.exists())
{
return console.log('A Notification has been deleted from the database : ', notification_id);
}
if (!change.after.exists())
{
return console.log('A notification has been deleted from the database:', notification);
return null;
}
const deviceToken = admin.database().ref(`/USER/${UserId}/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');
});
});
});

Categories