How to get inner child in cloud function for Firebase? - node.js

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.

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.

Retrieve single value onWrite firebase cloud Function

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.

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

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 query firebase realtime database in cloud code

I am using Firebase cloud code and firebase realtime database.
My database structure is:
-users
-userid32
-userid4734
-flag=true
-userid722
-flag=false
-userid324
I want to query only the users who's field 'flag' is 'true' .
What I am doing currently is going over all the users and checking one by one. But this is not efficient, because we have a lot of users in the database and it takes more than 10 seconds for the function to run:
const functions = require('firebase-functions');
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
exports.test1 = functions.https.onRequest((request, response) => {
// Read Users from database
//
admin.database().ref('/users').once('value').then((snapshot) => {
var values = snapshot.val(),
current,
numOfRelevantUsers,
res = {}; // Result string
numOfRelevantUsers = 0;
// Traverse through all users to check whether the user is eligible to get discount.
for (val in values)
{
current = values[val]; // Assign current user to avoid values[val] calls.
// Do something with the user
}
...
});
Is there a more efficient way to make this query and get only the relevant records? (and not getting all of them and checking one by one?)
You'd use a Firebase Database query for that:
admin.database().ref('/users')
.orderByChild('flag').equalTo(true)
.once('value').then((snapshot) => {
const numOfRelevantUsers = snapshot.numChildren();
When you need to loop over child nodes, don't treat the resulting snapshot as an ordinary JSON object please. While that may work here, it will give unexpected results when you order on a value with an actual range. Instead use the built-in Snapshot.forEach() method:
snapshot.forEach(function(userSnapshot) {
console.log(userSnapshot.key, userSnapshot.val());
}
Note that all of this is fairly standard Firebase Database usage, so I recommend spending some extra time in the documentation for both the Web SDK and the Admin SDK for that.

Resources