I believe that this cloud function is not idempotent
schevtso opened this issue · 3 comments
snippets-node/firestore/solution-aggregation/functions/index.js
Lines 11 to 37 in 9ae3a00
If it's retried, I think it's possible to get a wrong value for newNumRatings.
exports.aggregateRatings = functions.firestore
.document('restaurants/{restId}/ratings/{ratingId}')
.onWrite((change, context) => {
// Get value of the newly added rating
var ratingVal = change.after.data().rating;
// Get a reference to the restaurant
var restRef = db.collection('restaurants').doc(context.params.restId);
// Update aggregations in a transaction
return db.runTransaction(transaction => {
return transaction.get(restRef).then(restDoc => {
// Compute new number of ratings
var newNumRatings = restDoc.data().numRatings + 1;
// Compute new average rating
var oldRatingTotal = restDoc.data().avgRating * restDoc.data().numRatings;
var newAvgRating = (oldRatingTotal + ratingVal) / newNumRatings;
// Update restaurant info
return transaction.update(restRef, {
avgRating: newAvgRating,
numRatings: newNumRatings
});
});
});
});
exports.aggregateRatings = functions.firestore
.document('restaurants/{restId}/ratings/{ratingId}')
.onWrite((change, context) => {
// Get value of the newly added rating
var ratingVal = change.after.data().rating;
// Get a reference to the restaurant
var restRef = db.collection('restaurants').doc(context.params.restId);
// Update aggregations in a transaction
return db.runTransaction(transaction => {
return transaction.get(restRef).then(restDoc => {
// Compute new number of ratings
var newNumRatings = restDoc.data().numRatings + 1;
// Compute new average rating
var oldRatingTotal = restDoc.data().avgRating * restDoc.data().numRatings;
var newAvgRating = (oldRatingTotal + ratingVal) / newNumRatings;
// Update restaurant info
return transaction.update(restRef, {
avgRating: newAvgRating,
numRatings: newNumRatings
});
});
});
});
exports.aggregateRatings = functions.firestore
.document('restaurants/{restId}/ratings/{ratingId}')
.onWrite((change, context) => {
// Get value of the newly added rating
var ratingVal = change.after.data().rating;
// Get a reference to the restaurant
var restRef = db.collection('restaurants').doc(context.params.restId);
// Update aggregations in a transaction
return db.runTransaction(transaction => {
return transaction.get(restRef).then(restDoc => {
// Compute new number of ratings
var newNumRatings = restDoc.data().numRatings + 1;
// Compute new average rating
var oldRatingTotal = restDoc.data().avgRating * restDoc.data().numRatings;
var newAvgRating = (oldRatingTotal + ratingVal) / newNumRatings;
// Update restaurant info
return transaction.update(restRef, {
avgRating: newAvgRating,
numRatings: newNumRatings
});
});
});
});