Reputation: 719
Having an application in which an user can rate another user pictures, I would like to have a count of the total votes that an user has received. The best way I have found to achieve this goal with Firebase is to control the 'onWrite' event and update manually the counter for every user when it receives a vote.
The problem I've found with the following code is that the 'votesCount' is not updated exactly on the first 'onWrite' event, but it is updated in the next 'onWrite' event with the rate for the previous user. Why is this happening? is this a good approach for a voting application?
The purpose of the following method is to check if the voted user has 'votes_count', if true, add the new value to the old, in the opposite case just add the new value.
exports.updateVotesCount = functions.database.ref('/votes/{id}').onWrite(event => {
const data = event.data.val();
var votesCount = admin.database().ref('/profiles/' + data.to).child('votes_count');
votesCount.once('value').then(function(snapshot) {
if (snapshot.val()) {
votesCount.set(snapshot.val() + data.rate);
} else {
votesCount.set(data.rate);
}
});
});
This is the aspect of the data structure that I am using:
{
profiles: [
userId: {
name: "...",
image: "...",
votes_count: "..."
},
...
],
votes: [
voteId: {
from: "userId",
to: "userId",
rate: n
},
...
]
Upvotes: 1
Views: 792
Reputation: 13123
No, you should use a transaction for incrementing values. You also did not return a value, so your function would timeout. Returning is nessecary in Cloud Functions.
Your code should look like this:
exports.updateVotesCount = functions.database.ref('/votes/{id}').onWrite(event => {
const data = event.data.val();
return admin.database().ref('/profiles/' + data.to).child('votes_count').transaction(function(votes) {
if (event.data.exists()){ //If there is a onCreate action (user adds a vote) or use your own snapshot.val()
return (votes || 0) + 1; //providing a default "0" value if there is no value
}else{ // if there is a onDelete action (user removes avote)
return (votes || 1) - 1; //providing a default "1" value if there is no value
}
})
})
I could however not test the code, but I think it should work... Note that the value will increment when the user adds a value to the given path, and the value will decrement when the user removes at the given path, but you can change this easy like I said in my example.
Upvotes: 1