how to set value to zero of key-value pair object which i got in firebase cloud function(snapshot) - firebase

i have created cloud function which will trigger onCreate() when new value is add to node Sample/Pen.whenever the new node is created in Sample/Pen, i wanted to create another node which is Final/Pen but the values of key-value pair should be zero.

The following will do the job:
exports.finalPen = functions.database
.ref('/Sample/Pen/{penId}')
.onCreate((snap, context) => {
const createdData = snap.val(); // data that was created
return admin
.database()
.ref('Final/Pen/' + snap.key)
.set(setAllToZero(createdData));
});
const setAllToZero = function(pen) {
Object.keys(pen).forEach(function(key) {
pen[key] = 0;
});
return pen;
};

Related

Firebase Cloud Function not executing

I'm working on the group functionality of my app where members of the group can add task to a group that they are currently working on. So, when a task is added I want to notify all members using FCM that a task had been added to the group.
EDIT:
The code to add the task to a group is run on the client and works successfully. The purpose of the cloud function is just to send cloud messages to all the members of the group that a task has been added by a particular member.
This is my logic for the cloud function :
1st. As a task can be added to multiple groups at a time I'm using a forEach().
2nd. I'm fetching the uids of the Members in the groups and pushing them into an array(uids) so that later I can retrieve their fcmTokens.
3rd. Running a forEach on the uids to retrieve the fcmTokens.
4th.Sending Cloud message to devices.
But the cloud function doesn't execute as expected.
This my cloud function:
exports.newTaskAdded = functions.https.onCall(async (data, context) => {
const groups = data.groups; //Can be multiple groups hence an array.
const uid = data.uid;
const author = data.author;
const taskId = data.taskId;
const taskTitle = data.taskTitle;
try {
groups.forEach(async group => {
const groupName = group.groupName;
console.log('groupName: ', groupName);
const groupId = groups.groupId;
const membersPromises = [];
membersPromises.push(
admin
.firestore()
.collection('Groups')
.doc(`${groupId}`)
.collection('Members') //Members collection has document for each user with their uid as the document name.
.get(),
);
console.log('memberPromises: ', membersPromises);//Function stops after this.
const membersSnapshot = await Promise.all(membersPromises);
console.log('membersSnapshots', membersSnapshot);
const uids = [];
membersSnapshot.forEach(doc => {
doc.forEach(snap => {
console.log(snap.id);
uids.push(snap.id);
});
});
console.log(uids);
const uidPromises = [];
uids.forEach(uid => {
uidPromises.push(
admin
.firestore()
.collection('Users')
.doc(`${uid}`)
.get(),
);
});
console.log('uidPromises: ', uidPromises);
const tokensSnapshots = await Promise.all(uidPromises);
const notifPromises = [];
tokensSnapshots.forEach(snap => {
console.log(snap.data());
const token = Object.keys(snap.data().fcmTokens);
const payload = {
notification: {
title: `${author} has added a new task to ${groupName}`,
body: `Task Added: ${taskTitle}`,
sound: 'default',
},
};
notifPromises.push(admin.messaging().sendToDevice(token, payload));
});
await Promise.all(notifPromises);
});
} catch (err) {
console.log(err);
}
return {result: 'OK'};
});
This is my log:
As you can see there is no error shown.
Help would be very much appreciated. Thank you

How to create listener to custom variable inside document

This code updating when any change inside document but I want when change custom variable not any variable.
For example I want call this funcation when change Score variable.
exports.updateUser = functions.firestore.document('Test/uhfL5NE199eYTGyfSH1srtrtee').onUpdate((change, context) => {
const washingtonRef = admin.firestore().collection('Test').doc('uhfL5NE199eYTGyfSH1srtrtee');
return washingtonRef.update({Counts:admin.firestore.FieldValue.increment(1)});
});
This is not possible. With Cloud Function and Firestore an .onUpdate() is triggered when a document already exists and has any value changed (See https://firebase.google.com/docs/functions/firestore-events).
What you can do is to use the two snapshots that represent the data state before and after the triggering event and that are present in the change object, as follows:
exports.updateUser = functions.firestore.document('Test/uhfL5NE199eYTGyfSH1srtrtee').onUpdate((change, context) => {
const newValue = change.after.data();
const previousValue = change.before.data();
//Check if the Score field has changed
if (newValue.Score !== previousValue.Score) {
//Score field has changed! -> Do whatever you want
} else {
//End the Cloud Function
return false;
}
});

firestore cloud function, way to delete chat messages

I`m studying cloud function right now and I saw this sample code
'use strict';
const functions = require('firebase-functions');
// Max number of lines of the chat history.
const MAX_LOG_COUNT = 5;
// Removes siblings of the node that element that triggered the function
if there are more than MAX_LOG_COUNT.
// In this example we'll keep the max number of chat message history to
MAX_LOG_COUNT.
exports.truncate =
functions.database.ref('/chat/{messageid}').onWrite(async (change) => {
const parentRef = change.after.ref.parent;
const snapshot = await parentRef.once('value');
if (snapshot.numChildren() >= MAX_LOG_COUNT) {
let childCount = 0;
const updates = {};
snapshot.forEach((child) => {
if (++childCount <= snapshot.numChildren() - MAX_LOG_COUNT) {
updates[child.key] = null;
}
});
// Update the parent. This effectively removes the extra children.
return parentRef.update(updates);
}
return null;
});
how do I convert this to Firestore version from RTDB?
thank you

Firestore how to get last document of collection and add new with incremented id?

I have probably made a mistake with autogenerated id's for documents inside my events collection. I have added eventId for generated events and assigned eventId manually to each event.
Can I somehow get last document with its eventId and add new document with eventId of last document incremented by one.
Or should I delete autogenerated Id - based events and create new ones with non-autogenrated ids?
GitHub: https://github.com/Verthon/event-app
I have posted working React.js app on netlify: https://eventooo.netlify.com/
How it works:
I added unique eventId to each dummy events inside of events collection,
Based on that unique eventId I create link to specific single Event.js,
User can create event providing information in /create-event,
Once someone is creating an event I would like to add event to events collection with increment id, I have added 7 events created inside of console, so next should have id=7, something maybe like event1, event2 ... with autoincrement
Inside of users collection I store currentUser.uid from auth and host name provided by user
Event Creator
submitEvent = (e) => {
e.preventDefault();
const eventRef = this.props.firebase.db.collection("events").doc();
eventRef.set({
title: this.state.title,
host: this.state.host,
localization: this.state.localization,
description: this.state.description,
category: this.state.category,
day: this.state.day,
hour: this.state.hour,
featuredImage: this.state.imageUrl,
uid: this.props.firebase.auth.currentUser.uid
});
const citiesRef = this.props.firebase.db.collection("cities").where("city", "==", this.state.localization);
const cityRef = this.props.firebase.db.collection("cities").doc();
citiesRef.get()
.then(querySnapshot => {
if(querySnapshot.exists){
console.log("exist");
return
}else{
cityRef.set({
city: this.state.localization,
})
}
});
const userRef = this.props.firebase.db.collection("users").doc();
userRef.set({
user: this.state.host,
uid: this.props.firebase.auth.currentUser.uid
});
Thank you
I understand that you want your eventId value to come from a number sequence. The best approach for such need is to use a distributed counter, as explained in the doc: https://firebase.google.com/docs/firestore/solutions/counters
I don't know which language you are using, but I paste below the JavaScript code of the three functions from this documentation and I write the code that will generate the sequential number that you can use to create the documents.
var db = firebase.firestore();
//From the Firebase documentation
function createCounter(ref, num_shards) {
var batch = db.batch();
// Initialize the counter document
batch.set(ref, { num_shards: num_shards });
// Initialize each shard with count=0
for (let i = 0; i < num_shards; i++) {
let shardRef = ref.collection('shards').doc(i.toString());
batch.set(shardRef, { count: 0 });
}
// Commit the write batch
return batch.commit();
}
function incrementCounter(db, ref, num_shards) {
// Select a shard of the counter at random
const shard_id = Math.floor(Math.random() * num_shards).toString();
const shard_ref = ref.collection('shards').doc(shard_id);
// Update count
return shard_ref.update(
'count',
firebase.firestore.FieldValue.increment(1)
);
}
function getCount(ref) {
// Sum the count of each shard in the subcollection
return ref
.collection('shards')
.get()
.then(snapshot => {
let total_count = 0;
snapshot.forEach(doc => {
total_count += doc.data().count;
});
return total_count;
});
}
//Your code
var ref = firebase
.firestore()
.collection('counters')
.doc('1');
var num_shards = 2 //Adapt as required, read the doc
//Initialize the counter bay calling ONCE the createCounter() method
createCounter(ref, num_shards);
//Then, when you want to create a new number and a new doc you do
incrementCounter(db, ref, num_shards)
.then(() => {
return getCount(ref);
})
.then(count => {
console.log(count);
//Here you get the new number form the sequence
//And you use it to create a doc
db.collection("events").doc(count.toString()).set({
category: "education",
//....
})
});
Without much details on the Functional Requirements it is difficult to say if there is a difference between using the number form the sequence as the uid of the doc or as a field value in the document. It depends on the queries you may do on this collection.

How to Count Users with a Firebase Cloud Function (getting Function Returned Undefined error)

I have a Firebase Cloud Function that assigns a number to a user on onWrite. The following code works but something is wrong because the console logs state Function returned undefined, expected Promise or value.
I'm also not sure how to refer to the root from inside the onWrite so I've created several "parent" entries that refer to each other. I'm sure there is a better way.
onWrite triggers on this:
/users/{uid}/username
The trigger counts the children in /usernumbers and then writes an entry here with the uid and the child count + 1:
/usernumbers/uoNEKjUDikJlkpLm6n0IPm7x8Zf1 : 5
Cloud Function:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.setCount = functions.database.ref('/users/{uid}/username').onWrite((change, context) => {
const uid = context.params.uid;
const parent1 = change.after.ref.parent; //uid
const parent2 = parent1.ref.parent; //users
const parent3usernumbers = parent2.ref.parent.child('/usernumbers/');
const parent3usernumbersuid = parent2.ref.parent.child('/usernumbers/'+uid);
parent3usernumbers.once("value")
.then(function(snapshot) {
var a = snapshot.numChildren();
return parent3usernumbersuid.transaction((current) => {
return (a + 1);
}).then(() => {
return console.log('User Number Written', uid, a);
});
});
});
Is there a better way to do this? How can I get the Function Returned Undefined error to go away?
I should also mention it takes a few seconds for the 'usernumber' entry to be written. I'm guessing it's waiting for the function to return something.
Your function have to return a Promise :
exports.setCount = functions.database.ref('/users/{uid}/username').onWrite((change, context) => {
const uid = context.params.uid;
const parent1 = change.after.ref.parent; //uid
const parent2 = parent1.ref.parent; //users
const parent3usernumbers = parent2.ref.parent.child('/usernumbers/');
const parent3usernumbersuid = parent2.ref.parent.child('/usernumbers/'+uid);
return new Promise((resolve, reject) => {
parent3usernumbers.once("value").then(function(snapshot) {
var a = snapshot.numChildren();
return parent3usernumbersuid.transaction((current) => {
return (a + 1);
}).then(() => {
console.log('User Number Written', uid, a);
resolve({uid : uid, a : a})
}).catch(function(e) {
reject(e)
})
});
});
});

Resources