Reputation: 544
I have a firebase cloud function that is supposed to send a notification to the 5 closest phones when a new "emergency" is added to the database. The code I wrote does send a notification to the 5 closest phones, but It sends that same notification over and over again. It gets even worse when my users log on or off because then it sends even more. I'm confused why my cloud function doesn't just operate once and then terminate.
Here is the code for my cloud function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendPushNotificationAdded = functions.database.ref('/emergencies/{id}').onCreate(event => {
return admin.database().ref('/tokens').on('value', function(snapshot) {
var efarArray = snapshotToArray(snapshot, event.data.child('latitude').val(), event.data.child('longitude').val());
efarArray.sort(function(a, b) {
return a.distance - b.distance;
});
var payload = {
notification: {
title: "NEW EMERGANCY!",
body: "Message from Patient: " + event.data.child('other_info').val(),
//badge: '1',
sound: 'default',
}
};
var options = {
priority: "high",
timeToLive: 0
};
tokens_to_send_to = [];
if(efarArray.length >= 5){
//only send to the 5 closest efars
for (var i = 4; i >= 0; i--) {
tokens_to_send_to.push(efarArray[i].token);
}
}else{
for (var i = efarArray.length - 1; i >= 0; i--) {
tokens_to_send_to.push(efarArray[i].token);
}
}
//TODO: send a messaged back to patient if no efars respond or are found?
return admin.messaging().sendToDevice(tokens_to_send_to, payload, options).then(response => {
});
});
});
//code for function below from https://ilikekillnerds.com/2017/05/convert-firebase-database-snapshotcollection-array-javascript/
function snapshotToArray(snapshot, incoming_latitude, incoming_longitude) {
var returnArr = [];
snapshot.forEach(function(childSnapshot) {
var distance_to_efar = distance(childSnapshot.child('latitude').val(), childSnapshot.child('longitude').val(), incoming_latitude, incoming_longitude);
var item = {
latitude: childSnapshot.child('latitude').val(),
longitude: childSnapshot.child('longitude').val(),
token: childSnapshot.key,
distance: distance_to_efar
};
returnArr.push(item);
});
return returnArr;
};
If more clarification or code is needed just let me know. I've been stuck on this forever...
Upvotes: 1
Views: 652
Reputation: 317828
Don't use on() with Cloud Functions. That's almost never the right thing to use, since it adds a listener that could be invoked any number of times as the database changes. Use once() to get a single snapshot and act on that.
Also, you must return a promise from the function that resolves when all the asynchronous work in that function is complete. on() doesn't return a promise, so your function isn't doing that as well.
You might want to study some of the official sample code and follow the patterns established there.
Upvotes: 3