snippets-node icon indicating copy to clipboard operation
snippets-node copied to clipboard

I believe that this cloud function is not idempotent

Open schevtso opened this issue 6 years ago • 3 comments

https://github.com/firebase/snippets-node/blob/9ae3a00985b53025fdc82716046882af71b6009d/firestore/solution-aggregation/functions/index.js#L11-L37

If it's retried, I think it's possible to get a wrong value for newNumRatings.

schevtso avatar Aug 08 '19 17:08 schevtso

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 
       }); 
     }); 
   }); 
 }); 

ghost avatar Jul 03 '22 17:07 ghost

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 
       }); 
     }); 
   }); 
 }); 

ghost avatar Jul 03 '22 17:07 ghost

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 
       }); 
     }); 
   }); 
 }); 

ghost avatar Jul 03 '22 17:07 ghost