'use strict'
const functions = require('firebase-functions');
const admin=require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification=functions.database.ref('/notifications/{user_id}/{notification_id }').onWrite((change,context) =>{
const user_id=context.params.user_id;
const notification_id=context.params.notification_id;
console.log('The user ID is :',user_id);
if(!change.after.val()){
return console.log('A notification has been deleted from 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');
return userQuery.then(userResult=>{
const userName=userResult.val();
const deviceToken=admin.database().ref(`/users/${user_id}/device_token`).once('value');
return deviceToken.then(result =>{
const token_id=result.val();
const payload={
notification:{
title:"Friend Request",
body:`${userName} has sent you request`,
icon:"default"
}
};
return admin.messaging().sendToDevice(token_id, payload);
});
});
});
});
TypeError: Cannot read property 'from' of null
at fromUser.then.fromUserResult (/user_code/index.js:22:47)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
The only line of code where you're accessing a property called from is here:
const from_user_id=fromUserResult.val().from;
Therefore, fromUserResult.val() must be returning null.
fromUserResult is a DataSnapshot type object. According to the API documentation for the val() method, it can return null if there is no data at the location of the query. So, you will have to check for that case in your code.
I have achieved sending a notification with sender's name using this 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_user_id}/{notification_id}')
.onWrite((data, context) =>
{
const receiver_user_id = context.params.receiver_user_id;
const notification_id = context.params.notification_id;
if(!data.after.val())
{
console.log('A notification has been deleted :' , notification_id);
return null;
}
const sender_user_id = admin.database().ref(`/Notifications/${receiver_user_id}/${notification_id}`).once('value');
return sender_user_id.then(fromUserResult =>
{
const from_sender_user_id = fromUserResult.val().from;
const userQuery = admin.database().ref(`/Users/${from_sender_user_id}/name`).once('value');
return userQuery.then(userResult =>
{
const senderUserName = userResult.val();
console.log('You have notification from :' , senderUserName);
const DeviceToken = admin.database().ref(`/Users/${receiver_user_id}/device_token`).once('value');
console.log('Checkpoint2');
return DeviceToken.then(result =>
{
const token_id = result.val();
const payload =
{
notification:
{
//from_sender_user_id : from_sender_user_id,
title: "New Chat Request",
body: `${senderUserName} wants to connect with you`,
icon: "default"
}
};
return admin.messaging().sendToDevice(token_id, payload).then(response =>
{
console.log('This was the notification Feature');
return null;
}).catch(error => {
console.error(error);
res.error(500);
});
});
});
});
});
Related
Platform: React Native (IOS target)
Hi,
I am trying to build a way to send push notifications ( it's basically an app simillar to any datting app where you click a user and it sends them a notification to let them know I want to connect).
The notifications are being received fine on Expo Go but I don't know how to target a specific individual? Do I need backend for this?
This is my code:
const ProfilesScreen: React.FC<Props> = ({ navigation, route }) => {
const [expoPushToken, setExpoPushToken] = useState("");
const [notification, setNotification] = useState(false);
const [notificationRes, setNotifcationRes] = useState([]);
const notificationListener = useRef();
const responseListener = useRef();
const [data, setData] = useState<any>([]);
const [notificationsSentUids, setNotificationSentUids] = useState<any>([]);
const [notificationsCount, setNotificationsCount] = useState<number>(0);
const [activeIndex, setActiveIndex] = useState<number>(0);
const [storageData, setStorageData] = useState({});
async function sendPushNotification(expoPushToken) {
const message = {
to: expoPushToken,
sound: "default",
title: "My message",
body: storageData
? `${storageData?.name} wants to connect with you`
: null,
data: { someData: "goes here" },
};
await fetch("https://exp.host/--/api/v2/push/send", {
method: "POST",
headers: {
Accept: "application/json",
"Accept-encoding": "gzip, deflate",
"Content-Type": "application/json",
},
body: JSON.stringify(message),
});
}
async function registerForPushNotificationsAsync() {
let token;
if (Device.isDevice) {
const { status: existingStatus } =
await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== "granted") {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== "granted") {
alert("Failed to get push token for push notification!");
return;
}
token = (await Notifications.getExpoPushTokenAsync()).data;
setExpoPushToken(token);
} else {
// alert("Must use physical device for Push Notifications");
}
return token;
}
useEffect(() => {
registerForPushNotificationsAsync().then(token => setExpoPushToken(token));
// This listener is fired whenever a notification is received while the app is foregrounded
notificationListener.current =
Notifications.addNotificationReceivedListener(notification => {
setNotification(notification);
});
// This listener is fired whenever a user taps on or interacts with a notification (works when app is foregrounded, backgrounded, or killed)
responseListener.current =
Notifications.addNotificationResponseReceivedListener(response => {
setNotifcationRes(response);
return () => {
Notifications.removeNotificationSubscription(
notificationListener.current
);
Notifications.removeNotificationSubscription(responseListener.current);
};
}, []);
return ....
};
I have a trigger that fires when an item is creating. Therefore, i want to see that when the item is created, all users who have a location that was saved in the item will receive a notification
import functions = require('firebase-functions');
import admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.firestore
.document('itens/{itenId}').onCreate((snap, context) => {
//You get the values of the newly created doc as follows:
const data = snap.data();
const name = data.name;
const location = data.location;
const payload = {
notification: {
title: "Avana - Está bater",
body: `Podes encontrar : ${name} em ${location}`, //Here we use value
sound: "default"
}
};
const options = {
priority: "high",
};
admin.messaging().sendToTopic("newItem", payload, options)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});
console.log("Notification sent!");
return null;
});
your solution is Firebase Geofire:
https://firebase.googleblog.com/2013/09/geofire-location-queries-for-fun-and.html
https://medium.com/google-cloud/firebase-is-cool-geofire-is-just-awesome-b7f2be5e0f0f#.x78gjws28
I am trying to do a push notification function whenever the database update sends a notification but the function gets an error at first
Error:
TypeError: Cannot read property 'val' of undefined
at exports.fcmSend.functions.database.ref.onCreate.event (/srv/index.js:9:31)
at cloudFunction (/srv/node_modules/firebase-functions/lib/cloud-functions.js:131:23)
at /worker/worker.js:825:24
at
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
my function
const functions = require('firebase-functions');
const admin = require("firebase-admin");
admin.initializeApp();
exports.fcmSend = functions.database.ref('/messages/{userId}/{messageId}').onCreate(event => {
console.log('event', event)
const message = event.after.val()
const userId = event.params.userId
const payload = {
notification: {
title: message.title,
body: message.body,
icon: "https://placeimg.com/250/250/people"
}
};
admin.database()
.ref(`/fcmTokens/${userId}`)
.once('value')
.then(token => token.val() )
.then(userFcmToken => {
return admin.messaging().sendToDevice(userFcmToken, payload)
})
.then(res => {
console.log("Sent Successfully", res);
})
.catch(err => {
console.log('err', err);
});
});
The onCreate() listener doesn't have an "after". Only onUpdate() and onWrite() have before and after. It should work just to do:
event.val();
I am developing android apps and using firebase functions for sending Notifications through firebase cloud messaging. I have not much knowledge on firebase functions. I tried some tutorials.
I am getting an error to firebase functions logs as below:
image link...error image
TypeError: Cannot read property 'from' of undefined
at admin.firestore.collection.doc.collection.doc.get.then.queryResult (/user_code/index.js:14:42)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
If you know solutions please edit my code and paste as an answer. Thanks in Advance.
My index code as below
'use-strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.firestore.document("Users/{user_id}/Notifications/{notification_id}").onWrite((change,context)=> {
const user_id = context.params.user_id;
const notification_id = context.params.notification_id;
console.log("USER ID : "+user_id+" NOTIFICATION ID "+notification_id);
return admin.firestore().collection("Users").doc(user_id).collection("Notifications").doc(notification_id).get().then(queryResult =>{
const from_user_id = queryResult.data().from;
const type = queryResult.data().type;
console.log("FROM_USER ID : "+from_user_id+" TYPE "+type);
const from_data = admin.firestore().collection("Users").doc(from_user_id).get();
const to_data = admin.firestore().collection("Users").doc(user_id).get();
return Promise.all([from_data, to_data]).then(result => {
const from_name = result[0].data().name;
const to_name = result[1].data().name;
const token_id = result[1].data().token_id;
const payload = {
notification: {
tag : from_user_id+"Follow",
title : "Request From : "+from_name,
icon : "follow_icon_for_notification",
color : "white",
sound : "TYPE_NOTIFICATION",
body : "Click here to accept Follow Request.",
click_action:"jony.Activities.ONFOLLOWREQUESTRECEIVED"
},
data : {
message : "Click here to accept Follow Request.",
user_id : from_user_id
}
};
return admin.messaging().sendToDevice(token_id, payload).then(result => {
var db = admin.firestore();
const FieldValue = require('firebase-admin').firestore.FieldValue;
var notificationRef = db.collection("Users").doc(user_id).collection("Notifications").doc(notification_id).delete();
return console.log("Follow notification sent");
});
});
});
});
Would you use change.after.data()?
See https://firebase.google.com/docs/functions/firestore-events .
"use-strict";
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.sendNotification = functions.firestore
.document("Users/{user_id}/Notifications/{notification_id}")
.onWrite((change, context) => {
const user_id = context.params.user_id;
const notification_id = context.params.notification_id;
console.log("USER ID : " + user_id + " NOTIFICATION ID " + notification_id);
console.log("change.after.exists:" + change.after.exists);
console.log("change.after.data():" + change.after.data());
const data = change.after.data();
const from_user_id = data.from;
const type = data.type;
console.log("FROM_USER ID : " + from_user_id + " TYPE " + type);
const from_data = admin
.firestore()
.collection("Users")
.doc(from_user_id)
.get();
const to_data = admin
.firestore()
.collection("Users")
.doc(user_id)
.get();
return Promise.all([from_data, to_data]).then(result => {
const from_name = result[0].data().name;
const to_name = result[1].data().name;
const token_id = result[1].data().token_id;
const payload = {
notification: {
tag: from_user_id + "Follow",
title: "Request From : " + from_name,
icon: "follow_icon_for_notification",
color: "white",
sound: "TYPE_NOTIFICATION",
body: "Click here to accept Follow Request.",
click_action: "jony.Activities.ONFOLLOWREQUESTRECEIVED"
},
data: {
message: "Click here to accept Follow Request.",
user_id: from_user_id
}
};
return admin
.messaging()
.sendToDevice(token_id, payload)
.then(result => {
var db = admin.firestore();
const FieldValue = require("firebase-admin").firestore.FieldValue;
var notificationRef = db
.collection("Users")
.doc(user_id)
.collection("Notifications")
.doc(notification_id)
.delete();
return console.log("Follow notification sent");
});
});
});
I am trying to make a notification function to deploy using cloud functions of firebase
I did the first part of the code and it was successfully done which is:
'use-strict'
const functions = require('firebase-functions');
//const paypal=require('paypal-rest-sdk');
const admin=require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification=functions.firestore
.document("Users/{user_id}/Notifications/{notification_id}")
onWrite((change, context)=>{
const user_id=context.params.user_id;
const notification_id=context.params.notification_id;
});
without returning promise and it was ok but when i tried to complete like this:
'use-strict'
const functions = require('firebase-functions');
//const paypal=require('paypal-rest-sdk');
const admin=require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification=functions.firestore
.document("Users/{user_id}/Notifications/{notification_id}")
.onWrite((change, context)=>{
const user_id=context.params.user_id;
const notification_id=context.params.notification_id;
return admin.firestore().collection("Users").doc(user_id)
.collection("Notifications")
.doc(notification_id)
.get()
.then(queryResult=>{
const from_user_id=queryResult.data().from;
const from_data=admin.firestore()
.collection("Users").doc(from_user_id).get();
const to_data=admin.firestore().collection("Users")
.doc(user_id).get();
return Promise.all([from_data,to_data]).then(result=>{
const from_name=result[0].data().name;
const to_name=result[1].data().name;
console.log("from :"+from_name+"TO"+to_name);
});
});
// console.log("user_id"+ user_id+ "notification_id"+notification_id);
});
I have these 2 errors in node.cm:
1-Avoid nesting promises
2-each then()should return a value
how can i fix this problem???
Send push notification through FCM and cloud function when a change in Firestore database
You can try like this
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.firestore
.document('/users/{documentId}')
.onWrite((change, context) => {
console.log("CHANGE in DOCUMENT ID : " + context.params.documentId);
// Fetch data using standard accessors
const userId = change.after.data().userId;
const ownerId = change.after.data().ownerId;
console.log('We have a new request UID:', userId, 'for owner:', ownerId);
const owner_data = admin.firestore().collection('users').doc(ownerId).get();
const user_data = admin.firestore().collection('users').doc(userId).get();
return Promise.all([owner_data, user_data]).then(result => {
const ownerFCMToken = result[0].data().fcmToken;
const userName = result[1].data().displayName;
console.log("OWNER Token : " + ownerFCMToken + " USER: " + userName);
const payload = {
notification: {
title: 'Test title!',
body: `${userName} sent you a following request.`
// icon: follower.photoURL
}
};
admin.messaging().sendToDevice(followedFCMToken, payload)
.then(function (response) {
console.log("Push response : " + response);
return response
})
.catch(function (error) {
console.error("Error in sending push");
});
});