Firebase cloud functions check db for non-existant data - javascript

I'm looking for how to check if a documents exists in my cloud functions
My functions belows works fine when just incrementing an existing value, but now I'm trying to add functionality where it checks to see if the previous value exists and if it doesn't set as 1.
I've tried a different methods but I get things like "snapshot.exists" or "TypeError: Cannot read property 'count' of undefined at docRef.get.then.snapshot
var getDoc = docRef.get()
.then(snapshot => {
if (typeof snapshot._fieldsProto.count !== undefined) {
console.log("haha3", snapshot._fieldsProto.count)
var count = Number(jsonParser(snapshot._fieldsProto.count, "integerValue"));
docRef.set({
count: count + 1
});
}
else {
docRef.set({
count: 1
});
}
});
below is the code for the exists() error
var getDoc = docRef.get()
.then(snapshot => {
if snapshot.exists() {
console.log("haha3", snapshot._fieldsProto.count)
var count = Number(jsonParser(snapshot._fieldsProto.count, "integerValue"));
docRef.set({
count: count + 1
});
}
else {
docRef.set({
count: 1
});
}
});
The error for this code is:
TypeError: snapshot.exists is not a function at docRef.get.then.snapshot

It seems like docRef either points to a collection or is a query. In that case your snapshot is of type QuerySnapshot.
To check if a query has any result, use QuerySnapshot.empty.

I kept getting errors saying either empty or exists were not functions (tried many iterations) so eventually I landed on just using an undefined check and it works perfectly.
var db = event.data.ref.firestore;
var docRef = db.collection(userID).doc("joined").collection("total").doc("count");
var getDoc = docRef.get()
.then(snapshot => {
console.log("augu1", snapshot)
if (snapshot._fieldsProto === undefined) {
console.log("digimon1")
docRef.set({
count: 1
});
}
else {
console.log("haha31", snapshot._fieldsProto.count)
var count = Number(jsonParser(snapshot._fieldsProto.count, "integerValue"));
docRef.set({
count: count + 1
});
}
});

It turns out the problem is much simpler than I imagined: DocumentSnapshot.exists is a read-only property, not a function. So the proper way to use it is:
if snapshot.exists()

Related

Trouble with Addition Assignment in Array from Firebase

I have a scenario where i need to query multiple collections at once and retrieve the values based on the collection name. I use Promise.all to do so and it works accordingly like so
var dbPromises = [];
dbPromises.push(
admin.firestore().collection("collection1").where("user_id", "==", uid).get(),
admin.firestore().collection("collection2").where("user_id", "==", uid).get(),
admin.firestore().collection("collection3").where("user_id", "==", uid).get(),
);
const promiseConst = await Promise.all(dbPromises);
promiseConst.forEach((qs) => {
if (qs.size > 0) {
if (qs.query._queryOptions.collectionId == "collection1") {
qs.docs.map((doc) => {
valuesArr1.push(doc.data().arr);
});
} else if (qs.query._queryOptions.collectionId == "Collection2") {
qs.docs.map((doc) => {
valuesArr2.push(doc.data());
});
} else if (qs.query._queryOptions.collectionId == "collection3") {
qs.docs.map((doc) => {
valuesArr3.push(doc.data());
});
}
} else {
return
}
});
for (var i=0; i < valuesArr1.length; i++) {
if (valuesArr1[i].desiredData) {
console.log('datas from for loop on datas array', valuesArr1[i].desiredData)
globalVariable += `<img src="${valuesArr1[i].desiredData}">`;
}
}
Once I do this I map the query snapshot I get and am able to retrieve the values up to this point like so
From the first collection I retrieve an array from a firestore document and then the following collections i just retrieve all documents from the collections. This all 'works' in that when I console.log into the functions console the data shows up exactly as expected. It's only when I want to iterate over the data and assign the results to a global variable to use elsewhere that strange behavior occurs.
The console.log shows the desired data in the functions console with no issues, but the output when I interpolate that data into the html and send it off in nodemailer I get the following result
undefined is always the first in the response when i use the += addition assignment operator, but if i just use the = assignment operator there's no undefined but I obviously don't get all the data I'm expecting.
There are no undefined values or documents in the collections that I'm retrieving, I've checked thoroughly and even deleted documents to make sure of it. After days of researching I've come to the conclusion it has to do with the asynchronous nature of the promise I'm working with and the data not being immediately ready when I iterate it.
Can someone help me understand what I'm doing wrong and how to fix it in node?
I figured out a solution to my problem and would like to share it in hopes it saves a future viewer some time.
Before, I was storing the results of the array from Firebase inside a global variable. To save some head scratching I'll post the code again below.
var globalVariableArray = []
var globalVariable
var dbPromises = [];
dbPromises.push(
admin.firestore().collection("DataCollection").where("user_id", "==", uid).get()
);
const promiseConst = await Promise.all(dbPromises);
promiseConst.forEach((qs) => {
if (qs.size > 0) {
if (qs.query._queryOptions.collectionId == "DataCollection") {
Promise.all(
qs.docs.map(doc => {
globalVariableArray = doc.data().arrayWithDesiredData;
})
);
}
else {
return
}
});
globalVariableArray.map(gv => {
globalVariable += `<p>gv.desiredData</p>` // <--- Right here is where the problem area was
})
var mailOptions = {
from: foo#blurdybloop.com,
to: 'bar#blurdybloop.com
subject: 'Almost but not quite',
html: `${globalVariable}`
};
The above code give the expected output, but the output would always have undefined first before the data showed. This happened no matter how the array from Firebase was iterated over.
After strengthening my Google-Fu, I worked out the following solution
var globalVariableArray = []
var globalVariable
var dbPromises = [];
dbPromises.push(
admin.firestore().collection("DataCollection").where("user_id", "==", uid).get()
);
const promiseConst = await Promise.all(dbPromises);
promiseConst.forEach((qs) => {
if (qs.size > 0) {
if (qs.query._queryOptions.collectionId == "DataCollection") {
Promise.all(
qs.docs.map(doc => {
globalVariableArray = doc.data().arrayWithDesiredData;
})
);
}
else {
return
}
});
var mailOptions = {
from: foo#blurdybloop.com,
to: 'bar#blurdybloop.com
subject: 'It works!!',
html: `${globalVariableArray.map(dataIWantedAllAlong => <p>dataIWantedAllAlong.desiredData</p> )}` <--- Here I simply loop through the array inside the interpolation blocks and voila! no more undefined showing up in the results
};
I perform the loop inside the brackets where I interpolate the dynamic data and am no longer getting that pesky undefined showing up in my emails.
Safe travels and happy coding to you all!

Wait for all Firebase data query requests before executing code

I am trying to fetch data from different collections in my cloud Firestore database in advance before I process them and apply them to batch, I created two async functions, one to capture the data and another to execute certain code only after all data is collected, I didn't want the code executing and creating errors before the data is fetched when i try to access the matchesObject after the async function to collect data is finished, it keeps saying "it cannot access a property matchStatus of undefined", i thought took care of that with async and await? could anyone shed some light as to why it is undefined one moment
axios.request(options).then(function(response) {
console.log('Total matches count :' + response.data.matches.length);
const data = response.data;
var matchesSnapshot;
var marketsSnapshot;
var tradesSnapshot;
var betsSnapshot;
matchesObject = {};
marketsObject = {};
tradesObject = {};
betsObject = {};
start();
async function checkDatabase() {
matchesSnapshot = await db.collection('matches').get();
matchesSnapshot.forEach(doc => {
matchesObject[doc.id] = doc.data();
console.log('matches object: ' + doc.id.toString())
});
marketsSnapshot = await db.collection('markets').get();
marketsSnapshot.forEach(doc2 => {
marketsObject[doc2.id] = doc2.data();
console.log('markets object: ' + doc2.id.toString())
});
tradesSnapshot = await db.collection('trades').get();
tradesSnapshot.forEach(doc3 => {
tradesObject[doc3.id] = doc3.data();
console.log('trades object: ' + doc3.id.toString())
});
betsSnapshot = await db.collection('bets').get();
betsSnapshot.forEach(doc4 => {
betsObject[doc4.id] = doc4.data();
console.log('bets object: ' + doc4.id.toString())
});
}
async function start() {
await checkDatabase();
// this is the part which is undefined, it keeps saying it cant access property matchStatus of undefined
console.log('here is matches object ' + matchesObject['302283']['matchStatus']);
if (Object.keys(matchesObject).length != 0) {
for (let bets of Object.keys(betsObject)) {
if (matchesObject[betsObject[bets]['tradeMatchId']]['matchStatus'] == 'IN_PLAY' && betsObject[bets]['matched'] == false) {
var sfRef = db.collection('users').doc(betsObject[bets]['user']);
batch11.set(sfRef, {
accountBalance: admin.firestore.FieldValue + parseFloat(betsObject[bets]['stake']),
}, {
merge: true
});
var sfRef = db.collection('bets').doc(bets);
batch12.set(sfRef, {
tradeCancelled: true,
}, {
merge: true
});
}
}
}
});
There are too many smaller issues in the current code to try to debug them one-by-one, so this refactor introduces various tests against your data. It currently won't make any changes to your database and is meant to be a replacement for your start() function.
One of the main differences against your current code is that it doesn't unnecessarily download 4 collections worth of documents (two of them aren't even used in the code you've included).
Steps
First, it will get all the bet documents that have matched == false. From these documents, it will check if they have any syntax errors and report them to the console. For each valid bet document, the ID of it's linked match document will be grabbed so we can then fetch all the match documents we actually need. Then we queue up the changes to the user's balance and the bet's document. Finally we report about any changes to be done and commit them (once you uncomment the line).
Code
Note: fetchDocumentById() is defined in this gist. Its a helper function to allow someCollectionRef.where(FieldPath.documentId(), 'in', arrayOfIds) to take more than 10 IDs at once.
async function applyBalanceChanges() {
const betsCollectionRef = db.collection('bets');
const matchesCollectionRef = db.collection('matches');
const usersCollectionRef = db.collection('users');
const betDataMap = {}; // Record<string, BetData>
await betsCollectionRef
.where('matched', '==', false)
.get()
.then((betsSnapshot) => {
betsSnapshot.forEach(betDoc => {
betDataMap[betDoc.id] = betDoc.data();
});
});
const matchDataMap = {}; // Record<string, MatchData | undefined>
// betIdList contains all IDs that will be processed
const betIdList = Object.keys(betDataMap).filter(betId => {
const betData = betDataMap[betId];
if (!betData) {
console.log(`WARN: Skipped Bet #${betId} because it was falsy (actual value: ${betData})`);
return false;
}
const matchId = betData.tradeMatchId;
if (!matchId) {
console.log(`WARN: Skipped Bet #${betId} because it had a falsy match ID (actual value: ${matchId})`);
return false;
}
if (!betData.user) {
console.log(`WARN: Skipped Bet #${betId} because it had a falsy user ID (actual value: ${userId})`);
return false;
}
const stakeAsNumber = Number(betData.stake); // not using parseFloat as it's too lax
if (isNaN(stakeAsNumber)) {
console.log(`WARN: Skipped Bet #${betId} because it had an invalid stake value (original NaN value: ${betData.stake})`);
return false;
}
matchDataMap[matchId] = undefined; // using undefined because its the result of `doc.data()` when the document doesn't exist
return true;
});
await fetchDocumentsById(
matchesCollectionRef,
Object.keys(matchIdMap),
(matchDoc) => matchDataMap[matchDoc.id] = matchDoc.data()
);
const batch = db.batch();
const queuedUpdates = 0;
betIdList.forEach(betId => {
const betData = betDataMap[betId];
const matchData = matchDataMap[betData.tradeMatchId];
if (matchData === undefined) {
console.log(`WARN: Skipped /bets/${betId}, because it's linked match doesn't exist!`);
continue;
}
if (matchData.matchStatus !== 'IN_PLAY') {
console.log(`INFO: Skipped /bets/${betId}, because it's linked match status is not "IN_PLAY" (actual value: ${matchData.matchStatus})`);
continue;
}
const betRef = betsCollectionRef.doc(betId);
const betUserRef = usersCollectionRef.doc(betData.user);
batch.update(betUserRef, { accountBalance: admin.firestore.FieldValue.increment(Number(betData.stake)) });
batch.update(betRef, { tradeCancelled: true });
queuedUpdates += 2; // for logging
});
console.log(`INFO: Batch currently has ${queuedUpdates} queued`);
// only uncomment when you are ready to make changes
// batch.commit();
}
Usage:
axios.request(options)
.then(function(response) {
const data = response.data;
console.log('INFO: Total matches count from API:' + data.matches.length);
return applyBalanceChanges();
}

Retrieve and assign gameId to multiple players in Cloud Function transaction

I've been following this tutorial and trying to add a third player to the game. Here is the source code that works for two players. Below is my data structure:
"matchmaking" : {
"32idNK8OndcujN8CFNe3VBTxsXL2" : {
"gameId" : "placeholder"
},
"LnMnOtdLJYbsRuTeUpeHfaAhpX32" : {
"gameId" : "placeholder"
},
"plpISHWWtuNJvhSlFwfik6DOHR53" : {
"gameId" : "placeholder"
}
}
I have a cloud function that is called every time a user joins the matchmaking room. Depending on whichever two users are available, the function generates a unique game room for all three users. I am not well-versed in Javascript so I've been struggling on this for a while.
How can I retrieve and assign the gameId value to three players during a transaction?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var database = admin.database();
exports.matchmaker = functions.database.ref('matchmaking/{playerId}')
.onCreate((snap, context) => {
var gameId = generateGameId();
database.ref('matchmaking').once('value').then(snapshot => {
var secondPlayer = null;
var thirdPlayer = null;
// add two players into the queue
snapshot.forEach(child => { // check that its not the playerId who just joined
var playerId = child.key
var gameId = child.val().gameId
if (gameId === "placeholder" && playerId !== context.params.playerId) {
secondPlayer = child;
}
});
snapshot.forEach(child => { // check that its not the playerId who just joined
var playerId = child.key
var gameId = child.val().gameId
if (gameId === "placeholder" && playerId !== secondPlayer.key && playerId !== context.params.playerId) {
thirdPlayer = child;
}
});
if (secondPlayer === null || thirdPlayer === null) return null; // one room needs three players
database.ref("matchmaking").transaction(function (matchmaking) {
console.log(matchmaking)
// ================================================
// PROBLEM STARTS HERE
// ================================================
console.log("playerId gameId:",context.params.playerId.gameId) // returns undefined
// If any of the players gets into another game during the transaction, abort the operation
if (matchmaking === null ||
context.params.playerId.gameId !== "placeholder" ||
matchmaking[secondPlayer.key].gameId !== "placeholder" ||
matchmaking[thirdPlayer.key].gameId !== "placeholder") return matchmaking;
// matchmaking.forEach(player => { // check that its not the playerId that just joined
// var playerId = player.key
// var gameId = player.val().gameId
// if (gameId !== "placeholder") {
// player["gameId"] = gameId;
// }
// });
context.params.playerId.gameId = gameId; // assign game id to player
matchmaking[secondPlayer.key].gameId = gameId;
matchmaking[thirdPlayer.key].gameId = gameId;
return matchmaking;
}).then(result => {
if (result.snapshot.child(context.params.playerId).val() !== gameId) return;
// ENDS HERE
// ================================================
var game = {
gameInfo: {
gameId: gameId,
playersIds: [context.params.playerId, secondPlayer.key, thirdPlayer.key]
},
turn: context.params.playerId
}
database.ref("games/" + gameId).set(game).then(snapshot => {
console.log("Game created successfully!")
return null;
}).catch(error => {
console.log(error);
});
return null;
}).catch(error => {
console.log(error);
});
return null;
}).catch(error => {
console.log(error);
});
});
function generateGameId() {
var possibleChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var gameId = "";
for (var j = 0; j < 20; j++) gameId += possibleChars.charAt(Math.floor(Math.random() * possibleChars.length));
return gameId;
}
I've been getting errors such as matchmaking.forEach is not a function or Cannot read property 'params' of undefined or Cannot read property 'val' of undefined
console.log(matchmaking) shows the following:
{ '32idNK8OndcujN8CFNe3VBTxsXL2': { gameId: 'placeholder' },
LnMnOtdLJYbsRuTeUpeHfaAhpX32: { gameId: 'placeholder' },
plpISHWWtuNJvhSlFwfik6DOHR53: { gameId: 'placeholder' } }
I would really appreciate any help.
Update:
Solution:
database.ref("matchmaking").transaction(function (matchmakingSnapshot) {
if (matchmakingSnapshot) {
matchmakingSnapshot[context.params.playerId].gameId = gameId; // assign game id to player
matchmakingSnapshot[secondPlayer.key].gameId = gameId;
matchmakingSnapshot[thirdPlayer.key].gameId = gameId;
return matchmakingSnapshot;
} else if ( // If any of the players gets into another game during the transaction, abort the operation
matchmakingSnapshot === null ||
context.params.playerId.gameId !== "placeholder" ||
matchmakingSnapshot[secondPlayer.key].gameId !== "placeholder" ||
matchmakingSnapshot[thirdPlayer.key].gameId !== "placeholder") {
return matchmakingSnapshot;
}
}).then(result => {
The problem was that when I was trying to update the gameId, the transaction returns a null data. I had to make sure matchmaingSnapshot is not null before accessing the context params playerId. I'm not sure why calling matchmakingSnapshot.val() returns function undefined, but yeah that's it!
You should not currently be getting the error `matchmaking.forEach is not a function`.
The ".forEach" function can work on an array or on a DataSnapshot (where it iterates over the children, providing a DataSnapshot of each in turn).
But if you have an Object, ".forEach" will give you the error message you describe. The code as it stands appears to be having "matchmaking" as a DataSnapshot, so it should be ok for ".forEach" at the moment.
Explanation for error: Cannot read property 'params' of undefined
I think you have accidentally inserted a variable name, instead of telling javascript to use the variable name's value
if (matchmaking === null ||
matchmaking.context.params.playerId.gameId !== "placeholder" ||
matchmaking.secondPlayer.key.gameId !== "placeholder" ||
matchmaking.thirdPlayer.key.gameId !== "placeholder"
) return matchmaking;
I think you don't mean matchmaking.secondPlayer.key.gameId. I think you mean matchmaking[secondPlayer].key.gameId, so that if secondPlayer is "ABC123", you would be referring to matchmaking.ABC123.key.gameId
Same for thirdPlayer.
Explanation for error: Cannot read property 'params' of undefined
Did you mean just context.params.playerId.gameId, not matchmaking.context.params.playerId.gameId? You might have added the "matchmaking" by mistake?
Exploring the error: TypeError: Cannot read property 'gameId' of undefined
If you get the above error with this:
matchmaking[context.params.playerId].key.gameId`
First, check that you need the step ".key". Looking at your object, it looks to me that ".gameId" comes straight after the matchmaking[playerId], with no ".key" needed. If you are sure you need the ".key", then I would debug as follows. Immediately before that statement, insert the following console logs.
console.log("playerId:",context.params.playerId)
console.log("matchmaking[context.params.playerId]:",
matchmaking[context.params.playerId])
Then check that the playerId is something sensible. If it isn't, console.log the entire context with
console.log("context:",JSON.stringify(context)) // This avoids getting something useless logged like `[Object object]`.
If the playerId is correct, you will then see if matchmaking has an entry for that player. This approach to debugging will eventually expose where the problem lies.
I think the final problem is the confusion between 'matchmaking' being a DataSnapshot versus a straightforward, writeable Object
This was hard for me to understand because matchmaking is currently a DataSnapshot, which is a somewhat confusing type of thing. It seems to get console.logged as though it is an object, but it isn't writeable.
I suggest we extract an actual object, as follows:
database.ref("matchmaking").transaction(function (matchmaking) {
let matchmakingObject = matchmaking.val();
// ... remainder of code as before, and then:
matchmakingObject[context.params.playerId.gameId] = gameId; // assign game id to player
matchmakingObject[secondPlayer.key].gameId = gameId;
matchmakingObject[thirdPlayer.key].gameId = gameId;
return matchmakingObject;
I hope this fixes things!
My way to avoid such problems is to ALWAYS call snapshots xxxxSnapshot. That way I never forget that while it may console.log as though it was an object, in reality it is some sort of mystery thing.
For example, if I was writing this code, I would call things as follows:
database.ref("matchmaking")
.transaction(function (matchmakingSnapshot) {
let matchmakingObject = matchmakingSnapshot.val();
// ... remainder of code as before, and then:
matchmakingObject[context.params.playerId.gameId] = gameId; // assign game id to player
matchmakingObject[secondPlayer.key].gameId = gameId;
matchmakingObject[thirdPlayer.key].gameId = gameId;
return matchmakingObject;
It's a bit ugly but less painful than trying to debug a name that has two powerfully different meanings that are easily conflated.

Firebase: Run a query synchronously

I am trying to set some user data depending on the no.of users already in my USERS COLLECTION. This even includes a userId which should be a number.
exports.setUserData = functions.firestore.document('/users/{documentId}')
.onCreate(event => {
return admin.firestore().collection('users')
.orderBy('userId', 'desc').limit(1)
.get().then(function(snapshot) {
const user = snapshot.docs[0].data();
var lastUserId = user.userId;
var userObject = {
userId: lastUserId + 1,... some other fields here
};
event.data.ref.set(userObject, {
merge: true
});
});
});
One issue I noticed here, quickly adding 2 users result in those documents having the same userId may be because the get() query is asynchronous?
Is there a way to make this whole setUserData method synchronous?
There is no way to make Cloud Functions run your function invocations sequentially. That would also be quite contrary to the serverless promise of auto-scaling to demands.
But in your case there's a much simpler, lower level primitive to get a sequential ID. You should store the last known user ID in the database and then use a transaction to read/update it.
var counterRef = admin.firestore().collection('counters').doc('userid');
return db.runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(counterRef).then(function(counterDoc) {
var newValue = (counterDoc.data() || 0) + 1;
transaction.update(counterRef, newValue);
});
});
Solution
var counterRef = admin.firestore().collection('counters').doc('userId');
return admin.firestore().runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(counterRef).then(function(counterDoc) {
var newValue = (counterDoc.data().value || 0) + 1;
transaction.update(counterRef, {
"value": newValue
});
});
}).then(t => {
admin.firestore().runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(counterRef).then(function(counterDoc) {
var userIdCounter = counterDoc.data().value || 0;
var userObject = {
userId: userIdCounter
};
event.data.ref.set(userObject, {
merge: true
});
});
})
});

Limit number of records in firebase

Every minute I have a script that push a new record in my firebase database.
What i want is delete the last records when length of the list reach a fixed value.
I have been through the doc and other post and the thing I have found so far is something like that :
// Max number of lines of the chat history.
const MAX_ARDUINO = 10;
exports.arduinoResponseLength = functions.database.ref('/arduinoResponse/{res}').onWrite(event => {
const parentRef = event.data.ref.parent;
return parentRef.once('value').then(snapshot => {
if (snapshot.numChildren() >= MAX_ARDUINO) {
let childCount = 0;
let updates = {};
snapshot.forEach(function(child) {
if (++childCount <= snapshot.numChildren() - MAX_ARDUINO) {
updates[child.key] = null;
}
});
// Update the parent. This effectively removes the extra children.
return parentRef.update(updates);
}
});
});
The problem is : onWrite seems to download all the related data every time it is triggered.
This is a pretty good process when the list is not so long. But I have like 4000 records, and every month it seems that I screw up my firebase download quota with that.
Does anyone would know how to handle this kind of situation ?
Ok so at the end I came with 3 functions. One update the number of arduino records, one totally recount it if the counter is missing. The last one use the counter to make a query using the limitToFirst filter so it retrieve only the relevant data to remove.
It is actually a combination of those two example provided by Firebase :
https://github.com/firebase/functions-samples/tree/master/limit-children
https://github.com/firebase/functions-samples/tree/master/child-count
Here is my final result
const MAX_ARDUINO = 1500;
exports.deleteOldArduino = functions.database.ref('/arduinoResponse/{resId}/timestamp').onWrite(event => {
const collectionRef = event.data.ref.parent.parent;
const countRef = collectionRef.parent.child('arduinoResCount');
return countRef.once('value').then(snapCount => {
return collectionRef.limitToFirst(snapCount.val() - MAX_ARDUINO).transaction(snapshot => {
snapshot = null;
return snapshot;
})
});
});
exports.trackArduinoLength = functions.database.ref('/arduinoResponse/{resId}/timestamp').onWrite(event => {
const collectionRef = event.data.ref.parent.parent;
const countRef = collectionRef.parent.child('arduinoResCount');
// Return the promise from countRef.transaction() so our function
// waits for this async event to complete before it exits.
return countRef.transaction(current => {
if (event.data.exists() && !event.data.previous.exists()) {
return (current || 0) + 1;
} else if (!event.data.exists() && event.data.previous.exists()) {
return (current || 0) - 1;
}
}).then(() => {
console.log('Counter updated.');
});
});
exports.recountArduino = functions.database.ref('/arduinoResCount').onWrite(event => {
if (!event.data.exists()) {
const counterRef = event.data.ref;
const collectionRef = counterRef.parent.child('arduinoResponse');
// Return the promise from counterRef.set() so our function
// waits for this async event to complete before it exits.
return collectionRef.once('value')
.then(arduinoRes => counterRef.set(arduinoRes.numChildren()));
}
});
I have not tested it yet but soon I will post my result !
I also heard that one day Firebase will add a "size" query, that is definitely missing in my opinion.

Categories

Resources