Retrieve single value onWrite firebase cloud Function - node.js

How to retrieve a single value (restaurant_token)from firebase RealTime when there is a new child added
my structure is :
-RestaurantsOrders
-- random Push key
--- restaurant token
[See screenshot for node.js firebase cloud function][1]
[See screenshot for Firebase DB reference][2]

Have a look at the doc: You need to do along the following lines
exports.sendNotif = functions.database.ref('/RestaurantOrders/{pushId}')
.onWrite((change, context) => {
// Grab the current value of what was written to the Realtime Database.
const original = change.after.val().restaurant_token;
// ....
await admin.messaging(...)...
return null;
});
Note the return null; at the end: have a look at this doc for more details on this key point.

Related

Listen for changes in a Firestore collection

Firestore has a specific documentation for listening documents changes, like add, modify or remove (https://firebase.google.com/docs/functions/firestore-events).
For example, I can use an export function like the following to listen for a new document.
const functions = require('firebase-functions');
exports.myFunction = functions.firestore
.document('my-collection/{docId}')
.onCreate((change, context) => { /* ... */ });
Currently I'm building a Cloud Function that inserts multiple documents by means of a batch writing mechanism like the following.
const colRef = firestore.collection(collectionName)
const batch = firestore.batch();
items.forEach(item => {
let docId = hashCode(item.title);
let docRef = colRef.doc(`${docId}`);
batch.set(docRef, {
index: `${item.index}`,
description: `${item.description}`,
title: `${item.title}`
});
});
return await batch.commit();
What I would like to achieve is the following: when I insert multiple documents into a collection, I need to send a push notification to my mobile client in order to let users know that new documents are available.
onCreate, onUpdate, onDelete or onWrite operate on a single document change and not in the entire collection.
Is there a way to listen when into a collection are added a bunch of elements?
Thanks,
Lorenzo
Cloud Firestore events trigger on document changes and each new document will trigger a Cloud Function. Instead you can use a Callable Cloud Function that adds runs batched write and also send the notification. For example:
exports.sendNotification = functions.https.onCall((data, context) => {
const { docs } = data;
// TODO:
// 1. Run Batched Write
// 2. Send notification to user
});
This will invoke only 1 Cloud Function for all documents instead of a function for each document.

Firebase function, increment a value

I have a firebase cloud function that should increment the value of a field when a new document is created. The function executes successfully as I can see this within the firebase logs, but it doesn't increment the value of the field.
exports.onFileAdded = functions.firestore.document("files/{id}").onCreate(async (change, context) => {
const file = change.data();
const hub = await getByCollectionAndId('hubs', file.hubId);
Firebase.firestore().collection('teams').doc(hub.teamId).set({tileCount: Firebase.database.ServerValue.increment(1)}, {merge: true});
});
As there are no errors, and the function executes successfully, what am I doing wrong?
The problem is:
Firebase.database.ServerValue.increment(1)
You're using the operator to increment a value on the Realtime Database, but you are using it on Cloud Firestore. While both databases are part of Firebase, they're completely separate, and the API for one doesn't apply to the other.
To fix the problem, use the increment operator for Firestore:
firebase.firestore.FieldValue.increment(1)
Also see my answer here: How to increment existing number field in Cloud Firestore

Using Firebase Cloud Functions to fan out data

I'm extremely new to using Firebase cloud functions, and I am struggling to find the error in my code. It is supposed to trigger on a firestore write and then copy that document into all of the user's feeds who follow that user who posted.
My current code is below:
exports.fanOutPosts = functions.firestore
.document('posts/{postId}')
.onCreate((snap, context) => {
var db = admin.firestore();
const post = snap.data();
const userID = post['author'];
const postCollectionRef = db.collection('friends').document(userID).collection('followers');
return postCollectionRef.get()
.then(querySnapshot => {
if (querySnapshot.empty) {
return null;
} else {
const promises = []
querySnapshot.forEach(doc => {
promises.push(db.collection('feeds').document(doc.key).collection('posts').document(post.key).update(data));
});
return Promise.all(promises);
}
});
});
So this successfully deploys to Firebase, but it receives this error when a document is created:
TypeError: db.collection(...).document is not a function
at exports.fanOutPosts.functions.firestore.document.onCreate (/workspace/index.js:22:60)
Line 22 is const postCollectionRef = db.collection('friends').document(userID).collection('followers');
I am unsure why this line is causing errors with the .get, but if anyone could point me in the right direction it would be much appreciated!
Given that this is the nodejs API, you'll want to use doc() instead of document(). Other languages might use document().
I found this info via the Admin SDK on CollectionReference https://googleapis.dev/nodejs/firestore/latest/CollectionReference.html
According to the reference, the collection should be defined as the following:
const postCollectionRef = db.collection(`friends/${userId}/followers`);
Using template literals will allow you to dynamically add variables into the collection ref.
I would also take a look into the else logic to use template literals within your return statement.

Firebase Admin Node.js Read/Write Database

It seems I can't find a proper way to use the read/write functions for admin in the Cloud Functions. I am working on a messaging function that reads new messages created in the Realtime Database with Cloud Functions Node.js and uses the snapshot to reference a path. Here is my initial exports function:
var messageRef = functions.database.ref('Messages/{chatPushKey}/Messages/{pushKey}');
var messageText;
exports.newMessageCreated = messageRef.onCreate((dataSnapshot, context) => {
console.log("Exports function executed");
messageText = dataSnapshot.val().messageContent;
var chatRef = dataSnapshot.key;
var messengerUID = dataSnapshot.val().messengerUID;
return readChatRef(messengerUID, chatRef);
});
And here is the function that reads from the value returned:
function readChatRef(someUID, chatKey){
console.log("Step 2");
admin.database.enableLogging(true);
var db;
db = admin.database();
var userInfoRef = db.ref('Users/' + someUID + '/User Info');
return userInfoRef.on('value', function(snap){
return console.log(snap.val().firstName);
});
}
In the firebase cloud functions log I can read all console.logs except for the one inside return userInfoRef.on.... Is my syntax incorrect? I have attempted several other variations for reading the snap. Perhaps I am not using callbacks efficiently? I know for a fact that my service account key and admin features are up to date.
If there is another direction I need to be focusing on please let me know.

How to get inner child in cloud function for Firebase?

Here is my database and I want to trigger onWrite event on children of PUBLISHED_CONTENT_LIKES. When I add another userId under publishedContentId1, I can identify contentId as publishedContentId1 in my cloud function using event.params.pushId.
exports.handleLikeEvent = functions.database.ref('/USER_MANAGEMENT/PUBLISHED_CONTENT_LIKES/{pushId}')
.onWrite(event => {
// Grab the current value of what was written to the Realtime Database.
//const userId = event.data.child(publishedContentId);
//const test = event.params.val();
const publishedContentId = event.params.pushId;
var result = {"publishedContentId" : "saw"}
// You must return a Promise when performing asynchronous tasks inside a Functions such as
// writing to the Firebase Realtime Database.
// Setting an "uppercase" sibling in the Realtime Database returns a Promise.
return event.data.ref.parent.parent.child('PUBLISHED_CONTENTS/'+publishedContentId).set(result);
});
However I want to get newly added userId as well. How to get that userId using above event?
You can get the data that is being written under event.data. To determine the new user ID:
event.data.val().userID
I recommend watching the latest Firecast on writing Database functions as it covers precisely this topic.

Resources