Firebase Cloud功能增量计数器



Per-Firebase云函数文档,"事件至少传递一次,但单个事件可能会导致多个函数调用。避免依赖于精确一次机制,并编写幂等函数">

当查看下面一个餐厅评级的firestore云函数文档示例时,他们使用增量计数器来计算评级总数通过使用幂等函数来保持这个计数器的准确性的一些最佳方法是什么

将context.eventId存储在子集合文档字段中,并且仅在新的context.eventId不同的情况下执行该函数是否合理?

function addRating(restaurantRef, rating) {
// Create a reference for a new rating, for use inside the transaction
var ratingRef = restaurantRef.collection('ratings').doc();
// In a transaction, add the new rating and update the aggregate totals
return db.runTransaction((transaction) => {
return transaction.get(restaurantRef).then((res) => {
if (!res.exists) {
throw "Document does not exist!";
}
// Compute new number of ratings
var newNumRatings = res.data().numRatings + 1;
// Compute new average rating
var oldRatingTotal = res.data().avgRating * res.data().numRatings;
var newAvgRating = (oldRatingTotal + rating) / newNumRatings;
// Commit to Firestore
transaction.update(restaurantRef, {
numRatings: newNumRatings,
avgRating: newAvgRating
});
transaction.set(ratingRef, { rating: rating });
});
});
}

将context.eventId存储在子集合中合理吗document字段,并且仅当context.eventId不同?

是的,对于您的用例,使用云函数eventId是使您的云函数幂等的最佳解决方案。我想你已经看过这个Firebase视频了。

在您获取问题中代码的Firebase文档中,您将在底部找到类似的云函数代码。为了检查ID=eventId的文档是否存在于专用的ratingUpdateIds子集合中,我对该代码进行了如下调整

exports.aggregateRatings = functions.firestore
.document('restaurants/{restId}/ratings/{ratingId}')
.onWrite(async (change, context) => {
try {
// Get value of the newly added rating
const ratingVal = change.after.data().rating;
const ratingUpdateId = context.eventId;
// Get a reference to the restaurant
const restRef = db.collection('restaurants').doc(context.params.restId);
// Get a reference to the ratingUpdateId doc
const ratingUpdateIdRef = restRef.collection("ratingUpdateIds").doc(ratingUpdateId);
// Update aggregations in a transaction
await db.runTransaction(async (transaction) => {
const ratingUpdateIdDoc = await transaction.get(ratingUpdateIdRef);
if (ratingUpdateIdDoc.exists) {
// The CF is retried
throw "The CF is being retried";
}
const restDoc = await transaction.get(restRef);
// Compute new number of ratings
const newNumRatings = restDoc.data().numRatings + 1;
// Compute new average rating
const oldRatingTotal = restDoc.data().avgRating * restDoc.data().numRatings;
const newAvgRating = (oldRatingTotal + ratingVal) / newNumRatings;
// Update restaurant info and set ratingUpdateIdDoc
transaction
.update(restRef, {
avgRating: newAvgRating,
numRatings: newNumRatings
})
.set(ratingUpdateIdRef, { ratingUpdateId })
});
return null;
} catch (error) {
console.log(error);
return null;
}
});

PS:我假设云函数eventId可以用作Firestore文档ID。我没有发现任何相反的文档或信息。如果使用eventId作为ID会有问题,因为您在云功能中执行事务(因此使用Admin SDK(,您可以根据字段值(存储eventId的位置(查询文档,而不是根据其ID通过引用获取文档。

相关内容

  • 没有找到相关文章