Push Notification from Firestore - javascript

I need to send notification when data change in my Cloud Firestore database. I have this fields
I need to get the all users tokens and send the push notification. I have a code, but this only give me a token if i know the user name this is my code :
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.useWildcard = functions.firestore
.document('notification/{id}')
.onWrite((change, context) => {
const payload = {
notification: {
title: 'Message from Cloud',
body: 'This is your body',
badge: '1',
sound: 'default'
}
};
admin.firestore().collection('notification').doc('fcm-token').get().then(doc => {
console.log("Token: " + doc.data().user1.token);
});
});

To loop over all users in the document:
admin.firestore().collection('notification').doc('fcm-token').get().then(doc => {
let data = doc.data();
Object.keys(data).forEach((user) {
console.log("Token: " + data[user].token);
});
});
But as Doug commented: storing the tokens for all users in a single document is bound to become a scalability problem at some point.

Related

Sending content from snapshot as push notification

I want to send the user a push notification with cloud functions on Firebase if someone commented to a topic on his iOS Device.
This code below works fine if I put the content of the notification manually.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.Push = functions.database.ref('/placeID/{pushId}/')
.onCreate((snapshot, context) => {
var topic = 'weather';
const payload = {
notification: {
title: 'User Max',
body: 'Hi how are you?',
badge: '1',
sound: 'default'
}
};
admin.messaging().sendToTopic(topic,payload);
})
In the next step I want to get the content of the comment the person has sent. Kinda get the value of the snapshot.
I tried it like this and get no error in the Logs Explorer from Google. But also no Push Notification anymore.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.Push = functions.database.ref('/placeID/{autogeneratedplaceID}/')
.onCreate((snapshot, context) => {
var username = snapshot.child("userName").val()
var usercomment = snapshot.child("userComment").val()
var topic = 'weather';
const payload = {
notification: {
title: username,
body: usercomment,
badge: '1',
sound: 'default'
}
};
admin.messaging().sendToTopic(topic,payload);
})
What is wrong here? I also found a video on Youtube with the exact solution. But this is for android and it did not really help me. Youtube
This is how my firebase realtime database structure looks like.

firebase cloud functions for push notifications are not working

in my flutter app, i have saved every devices token to a collection in firebase database and i wrote the code for firebase cloud functions so it sends a message(notification) for every user that subscribed to a topic and have their token is in the tokens collection but it doesnt send anything when i add something to the topic i subscribed them to, heres my cloud functions code using javascrpit in the index file:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().functions);
var newData;
exports.myTrigger = functions.firestore.document('messages/{messageId}').onCreate(async (snapshot, context) => {
//
if (snapshot.empty) {
console.log('No Devices');
return;
}
newData = snapshot.data();
const deviceIdTokens = await admin
.firestore()
.collection('messages')
.get();
var tokens = [];
for (var tokened of deviceIdTokens.docs) {
tokens.push(tokened.data().token);
}
var payload = {
notification: {
title: 'Push Title',
body: 'Push Body',
sound: 'default',
},
data: {
message: newData.message,
click_action: 'FLUTTER_NOTIFICATION_CLICK',
},
};
try {
const response = await admin.messaging().sendToDevice(tokens, payload);
console.log('Notification sent successfully');
} catch (err) {
console.log(err);
}
});
and heres my database structure
and the tokens collection :
what am i doing wrong?
trying his instead :
i should have written :
'''
const deviceIdTokens = await admin
.firestore()
.collection('tokens')
.get()
'''
also for sending a message through the database i should have written "message" in the field because i named the "data"'s key "message" :)

Make many types of notification in same app in FCM by Functions which written by JavaScript in android/java

I build an app which i need to add in it many types of notifications but i can't do it with myself because am have tiny knowledge about JS
I tried to deploy many functions by differnt body , title ..etc but it seems not able to deploy many functions in Firebase Functions
'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/Noti/{receiver_user_id}/{notification_id}')
.onWrite((data, context) =>
{
const receiver_user_id = context.params.receiver_user_id;
const notification_id = context.params.notification_id;
console.log('We have a notification to send to :' , receiver_user_id);
if (!data.after.val())
{
console.log('A notification has been deleted :' , notification_id);
return null;
}
const DeviceToken = admin.database().ref(`/user/${receiver_user_id}/token`).once('value');
return DeviceToken.then(result =>
{
const token_id = result.val();
const payload =
{
notification:
{
title: "Open this notification now",
body: `I have a problem in my car `,
icon: "default" ,
sound: "default"
}
};
return admin.messaging().sendToDevice(token_id, payload)
.then(response =>
{
console.log('This was a notification feature.');
});
});
});
thats all i have to describe my issue
Yes, you can deploy various functions, but you need to set different names for each one of them. The function name is after exports., so you can have:
exports.sendNotification
exports.newMessageNotification
exports.newFollowerNotification
...
and each one of them will make what you wish them to do.

Firebase cloud function with nested promises

Im trying to send an email based on a collection onAdd event
the information i need to send the email comes from 3 different collections
so i was thinking to set all the data i need and then proceed to send the email, however , when i come to the actual email sending all the info is undefined, so clearly the variables are not set properly
here is my code
exports.sendRepairInitiatedEmail = functions.firestore.document('repairs/{id}').onCreate((snap, context) => {
const repair = snap.data(); <--- this is set correctly
let customer;
let configuration;
return admin
.firestore()
.collection('customers')
.doc(repair.customerId)
.get()
.then(dbCustomer => {
customer = dbCustomer; <--- customer seems undefined
return admin
.firestore()
.collection('configuration')
.where('clientId', '==', repair.clientId)
.get()
.then(conf => {
configuration = conf; <-- configuration seems undefined
console.log('Sending email to ' + customer.customerEmail);
const msg = {
to: customer.customerEmail,
from: configuration.companyEmail,
templateId: 'sendGridid',
dynamic_template_data: {
name: customer.customerName,
device: repair.device,
accessCode: repair.accessCode,
storeName: configuration.storeName,
phone: configuration.phoneNumber,
},
};
return sgMail.send(msg);
});
})
.then(() => console.log('Repair initiated email successfully sent to ' + customer.customerName));
});
code also looks complicated and i want to avoid so much promise nesting
any help would be much appreciated
You don't have to nest so many promises, why don't you try something like this:
exports.sendRepairInitiatedEmail = functions.firestore.document('repairs/{id}').onCreate((snap, context) => {
const repair = snap.data();
let getCustomer = admin
.firestore()
.collection('customers')
.doc(repair.customerId)
.get();
let getConfig = admin
.firestore()
.collection('configuration')
.where('clientId', '==', repair.clientId)
.get();
return Promise.all([getCustomer, getConfig])
.then(values => {
const [customer, configuration] = values;
console.log('Sending email to ' + customer.customerEmail);
const msg = {
to: customer.customerEmail,
from: configuration.companyEmail,
templateId: 'sendGridid',
dynamic_template_data: {
name: customer.customerName,
device: repair.device,
accessCode: repair.accessCode,
storeName: configuration.storeName,
phone: configuration.phoneNumber,
},
};
console.log('Repair initiated email successfully sent to ' + customer.customerName);
return sgMail.send(msg);
});
});
This code just uses all the returned values from the promises one after another without the need to make them available to a bigger scope.
Or alternatively, if possible you could turn the whole thing into async/await structure and it will look much cleaner, it will be something like this (untested):
exports.sendRepairInitiatedEmail = functions.firestore.document('repairs/{id}').onCreate(async (snap, context) => {
const repair = snap.data();
const customer = await admin
.firestore()
.collection('customers')
.doc(repair.customerId)
.get();
const configuration = await admin
.firestore()
.collection('configuration')
.where('clientId', '==', repair.clientId)
.get();
console.log('Sending email to ' + customer.customerEmail);
const msg = {
to: customer.customerEmail,
from: configuration.companyEmail,
templateId: 'sendGridid',
dynamic_template_data: {
name: customer.customerName,
device: repair.device,
accessCode: repair.accessCode,
storeName: configuration.storeName,
phone: configuration.phoneNumber,
},
};
console.log('Repair initiated email successfully sent to ' + customer.customerName);
return await sgMail.send(msg);
});

User name empty when sending notification with firebase

I want to send notification to users when they receive new messages with the below JavaScript code
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.pushNotification = functions.database.ref('/messages/{user_id}/{message_id}').onWrite( (change, context) => {
const user_id = context.params.user_id;
const message_id = context.params.message_id;
console.log('We Have A Notification for :', user_id);
if (!change.after.val()){
return console.log("A Notification Has Been Deleted From The Database: ", message_id)
}
const fromUser = admin.database().ref(`/messages/${user_id}/${message_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: "Chat+",
body: `You have a new notification from ${userName}`,
icon: "default",
click_action: "com.mani.eric.quickch_TARGET_NOTIFICATION"
},
};
return admin.messaging().sendToDevice(token_id, payload ).then(Response =>{
console.log('this is the notification')
});
});
});
});
the notification actually gets delivered but on both devices(sender and receiver gets same notification) with the user name of the sender as null.
my question now is, how can i retrieve the sender user name and display the notification only on the receivers device?
You have a type on the path that triggers the function:
functions.database.ref('/messages/{user_id/{message_id}')
Should be:
functions.database.ref('/messages/{user_id}/{message_id}')
So with a closing parenthesis after user_id.
Please read how to create a minimal, complete, verifiable example, as the code you shared is quite a bit more complex than needed to reproduce the problem. For example, your console.log('We Have A Notification for :', user_id); already should show that user_id is null, so the code after that can't work, and is irrelevant to the problem. Reducing the scope of the problem this way increases the chances that you'll find the cause yourself. Or at worst, it reduces the code we need to look at, which increases the chance that somebody will spot the problem and answer.

Categories

Resources