Firebase Functions - push notification when new document is created - firebase

I have the following Firestore DB structure:
users
$USER_ID
notifications
$DOC1
$DOC2
$DOC3
I want to push a new notification when a document is created at the user notification collection.
It should be something like this, but I don't know of any way to this for each $UID:
exports.newSubscriberNotification = functions.firestore
.document('users/$UID/notifications')
.onCreate(async event => {
How can I use Firebase Functions to do this? If there is no way, any suggestions for a workaround?

You should use the following code to trigger your Cloud Function:
exports.newSubscriberNotification = functions.firestore
.document('users/{userId}/notifications/{docId}')
.onCreate((snap, context) => {
//You get the values of the newly created doc as follows:
const newValue = snap.data();
console.log(newValue);
//You get the parameters as follows:
const userId = context.params.userId;
//console.log(userId);
const docId = context.params.docId;
//console.log(docId);
// You perform here the notification sending
});
For the code for the notification sending, have a look at this official Firebase Cloud Function sample: https://github.com/firebase/functions-samples/blob/master/fcm-notifications/functions/index.js

Related

Is there a way to get email or text notifications each time data is written to my Google Cloud Firestore bucket?

I have a google cloud bucket and firebase writes my app data there. I would like to monitor my data, and have any new update (write) to my firebase database it sent via a text or email to me. I currently have Twilio set up on Nodejs to send texts on Firebase and my code is:
const functions = require('firebase-functions');
var twilio = require('twilio');
const admin = require('firebase-admin');
admin.initializeApp();
var accountSid = 'account id'; // Account SID from www.twilio.com/console
var authToken = 'account token'; // Auth Token from www.twilio.com/console
var client = new twilio(accountSid, authToken);
exports.useWildcard = functions.firestore
.document('comments/{commentContent}')
.onWrite((change, context) => {
client.messages.create({
body: context.params.commentContent,
to: '+15555555555', // Text this number
from: '+15555555556' // From a valid Twilio number
})
.then((message) => console.log(message.sid));
});
Currently, I would like to build it out for just the comments document, which are organized inside firebase through comments/{commentContent}. Later, I would like to expand to other trees. I am however, unsure if the above will run each time there is a write to my comments tree. Does it require the firebase-admin module as I have put above? Thanks!
Yes, the onWrite method will not only run when there is a write to the comments tree, but will also be triggered by any change in any document and on the deletion of a document. This means that right now your code will responde in the same way to any of the above cases, and this could cause problems, especially in the case of a document being deleted since it will try to send a comment that doesent exist and will likely get some null exceptions.
Said that you have different solutions.
If you only want the function to react to a new comment, but not to an update or deletion you should use onCreate trigger instead of onWrite.
If you also want to handle a comment update notification you can use both onCreate and onUpdate, but sending different messages by doing something like:
exports.useWildcardCreate = functions.firestore
.document('comments/{commentContent}')
.onCreate((change, context) => {
client.messages.create({
body: context.params.commentContent,
to: '+15555555555', // Text this number
from: '+15555555556' // From a valid Twilio number
})
.then((message) => console.log(message.sid));
});
exports.useWildcardUpdate = functions.firestore
.document('comments/{commentContent}')
.onUpdate((change, context) => {
const newComment = change.after.data();
const previuosComment = change.before.data();
client.messages.create({
body: 'The comment ${previuosComment} has been changed to ${newComment}',
to: '+15555555555', // Text this number
from: '+15555555556' // From a valid Twilio number
})
.then((message) => console.log(message.sid));
});
At last if you also need to notify when a comment has been deleted you should use onWrite method but differentiating between the 3 different cases as shown below:
exports.useWildcard = functions.firestore
.document('comments/{commentContent}')
.onWrite((change, context) => {
var textBody;
const oldComment = change.before.data();
const newComment = change.after.data();
if (change.after.exists == false) { // comment has been deleted
textBody = 'The comment ${oldComment} has been deleted';
}
else if (oldComment != newComment) { // comment has been updated
textBody = 'The comment ${oldComment} has been changed to ${newComment}';
}
else { // if its not an update or a deletion its a new comment
textBody = newComment;
}
client.messages.create({
body: textBody,
to: '+15555555555', // Text this number
from: '+15555555556' // From a valid Twilio number
})
.then((message) => console.log(message.sid));
});
Finally require('firebase-admin') is needed since it will allow you to interact with Firebase from privileged environments. Here you can find all the information to the Firebase Admin SDK

Within a firebase project, can I update values in the firestore database from the real time database

There is an integer value in the my real time database that I'd like to have sync'd with an integer value in my firestore database. The realtime database is fed through an external source and when it gets an update, I'd like that pushed to the firestore database
Here's what I have so far, I am able to access the value in the realtime database but not the firestore database.
=============== Data Structure===================
Real Time database
user1:
{ meter : 20 }
Firestore database
Collection: Users
{Document : user1
{ meter : 20 }}
/// =============Code Sample ======================================
const functions = require('firebase-functions');
// Initialize the Firebase application with admin credentials
const admin = require('firebase-admin');
admin.initializeApp();
// Define user sync method
exports.meterSync = functions.database.ref('/user1/meter').onUpdate( (change, context) => {
// Get a reference to the Firestore document of the changed user
var userDoc = admin.firestore().doc(`user/${context.params.user1}`);
const meterReading = change.after.val();
console.log(meterReading);
console.log(userDoc); /// Not able to access this
return null
});
My expectation is that user doc will give me the document, so I can update the fields within it. But I am getting a documentReference object, not sure how to access the meter field.
By doing
var userDoc = admin.firestore().doc(`user/${context.params.user1}`);
You actually defined a DocumentReference.
You have to use this DocumentReference to write to the Firestore database, using the set() or update() methods.
Here is a code using the set() method:
exports.meterSync = functions.database
.ref('/{userId}/meter')
.onUpdate((change, context) => {
const meterReading = change.after.val();
console.log(meterReading);
// Get a reference to the Firestore document of the changed user
const userDoc = admin.firestore().doc(`user/${context.params.userId}`);
return userDoc.set(
{
meter: meterReading
},
{ merge: true }
);
});
You will need to use cloud functions for this, lets say, you have one background function:
export const one = functions.firestore.document('users').onWrite((change, context) => {
// ... Your code here
})
export const two = functions.database.ref('/users/{userId}')
.onCreate((snapshot, context) => {
// ... you code here
})
Since you have access to the firebase sdk admin in there you basically can achieve your goal. You can read more about it here

Making automated notifications with Firebase Cloud Functions, Messaging,Firestore

I've been trying to push notifications with .onUpdate() trigger but It doesn't work. I'm not sure what is wrong since anything I find on docs is useless pretty much and it's my first time working with Node.js.
I want to notify the user (with Firebase Messaging) when any product gets updated (in Firebase Realtime Database) using Firebase Cloud Functions, which is after submitting an order, and the requirement is that the product stock is <= 5.
Structure of the collection is like this:
products (collection) -> {productID} (document) -> attributes: {name, barcode, price, stock, sold}
//import firebase
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/products/{product}')
.onUpdate((change, context) => {
const prodName = context.data.child('name');
const numProd = context.data.child('stock');
if(numProd<=5){
const payload = {
notification: {
title: 'Low stock!',
body: `Product ${prodName} is running out.`
}
}
const registrationToken = 'token';
return admin.messaging().sendToDevice(registrationToken,payload)
.then(function(response){
console.log('Notification sent successfully:',response);
return 1;
})
.catch(function(error){
console.log('Notification sent failed:',error);
});
}
});
Apparently you are mixing up the two Firebase's database services: Firestore and the Realtime Database.
As a matter of fact, you indicate that your data is organised in collections ("Structure of the collection is like this: products (collection) -> {productID} (document)") which means that you are using Firestore (Realtime Database doesn't have collections).
But your background trigger is corresponding to a Realtime Database trigger, see https://firebase.google.com/docs/functions/database-events.
If the assumption that you are mixing up the two database services is right, you need to use a background trigger for Firestore, see https://firebase.google.com/docs/functions/firestore-events, in particular the onUpdate() one, as follows:
exports.updateUser = functions.firestore
.document('/products/{productId}')
.onUpdate((change, context) => {
// Get an object representing the document
const newValue = change.after.data();
const prodName = newValue.name;
const numProd = newValue.stock;
// ...
});
Note that it seems that you are not handling correctly the case when numProd > 5. You may throw an error or just do return null;
It is a also a good idea to watch the 3 videos about "JavaScript Promises" from the Firebase video series: https://firebase.google.com/docs/functions/video-series/.

How to send notification with functions firebase/firestore

I have a little problem. I want to send notifications when someone add comment to posts in my app. I dont use database only firestore. I have something like this for now.
export const sendNotification = functions.firestore
.document('Comments/{commentId}')
.onCreate((snap, context) => {
const senderUid = snap.get('idUser');
const receiverUid = snap.get('idUserImage');
const comment = snap.get('comment');
});
Now how to send ntification to receiverUid with text - comment?
You have to use Firebase Cloud Messaging.
Take a look on this example: https://github.com/flutter/plugins/blob/master/packages/firebase_messaging/example/lib/main.dart

dialogflow to interact with firebase realtime database

Is it possible to get some data from firebase database by using dialogflow? I'm new to dialogflow so I'm still doing some research about.
For example, I want to ask my chatbot if a doctor is available then chatbot will access the firebase db to check if that specific doctor is available or lets say schedule me an appoint with doc X so dialogflow will do a function that allow will enter a schedule object to the database
thanks.
You can use Firebase function to fulfill your Dialogflow agent and the Firestore database to store data. An example of how to do so with Dialogflow's Google Assistant integration is below:
const functions = require('firebase-functions');
const firebaseAdmin = require('firebase-admin');
const DialogflowApp = require('actions-on-google').DialogflowApp;
// Initialize Firebase Admin SDK.
firebaseAdmin.initializeApp(functions.config().firebase);
exports.dialogflowFulfillment = functions.https.onRequest((req, res) => {
// Log headers and body
console.log('Request headers: ' + JSON.stringify(req.headers));
console.log('Request body: ' + JSON.stringify(req.body));
// Create a new Dialgoflow app request handler
let app = new DialogflowApp({request: req, response: res});
// welcome function handler
function start(app) {
// Get user ID from the Google Assistant through Action on Google
let userId = app.getUser().userId;
// Check if the user is in our DB
admin.firestore().collection('users').where('userId', '==', userId).limit(1).get()
.then(snapshot => {
let user = snapshot.docs[0]
if (!user) {
// If user is not in DB, its their first time, Welcome them!
app.ask('Welcome to my app for the first time!');
// Add the user to DB
firebaseAdmin.firestore().collection('users').add({
userId: userId
}).then(ref => {
console.log('Added document with ID: ', ref.id);
});
} else {
// User in DB
app.ask('Welcome back!')
}
});
}
// Map function hanlder to Dialogflow's welcome intent action 'input.welcome'
const actionMap = new Map('input.welcome', start)
app.handleRequest(actionMap);
});

Resources