当一个新的review
被发布到子集合reviews
中时,我试图用一个事务来更新Firestore数据库中restaurant
文档的平均评级。下面的代码适用于评论缓慢进入的情况,但如果我在几秒钟内插入10条评论进行压力测试,它将不再正确更新平均评级(即,它可能只计算前5个评论,而不会基于其余的评论进行更新)。我对事务的理解是,当数据在其脚下发生变化时,它会自动重新运行,以确保正确更新值。
这里是使用的云函数。
exports.reviewCreated = functions.firestore.document('/restaurants/{restaurantid}/reviews/{reviewid}').onCreate((snapshot, context) => {
const rest_id = context.params.restaurantid;
const rest_ref = admin.firestore().collection('restaurants').doc(rest_id)
const rest_rating = snapshot.data().rest_rating;
console.log('The new rest rating is: ' + rest_rating);
try {
admin.firestore().runTransaction((t) => {
return t.get(rest_ref).then((rest_doc) => {
const new_total_reviews = rest_doc.data().totalReviews + 1;
const current_avg_rating = rest_doc.data().averageRating
const new_avg_rating = current_avg_rating + ((rest_rating - current_avg_rating)/new_total_reviews);
t.update(rest_ref, {totalReviews: new_total_reviews,
averageRating: new_avg_rating});
});
})
} catch (e) {
console.log('[Review Created] Transaction Failed', e);
return null;
}
});
为了测试这个。我在我的应用程序的调试屏幕上有一个按钮来插入一个假的评论,代码如下
<Button title = 'Add Review! (Test)'
onPress = {() =>
{
console.log(this.state.uid);
var new_uuid = uuid.v4();
firestore()
.collection('restaurants')
.doc(this.state.restid)
.collection('reviews')
.doc(new_uuid)
.set({
rest_rating: Math.floor(Math.random() * 5) + 1,
review_name: 'test'
});
}}
/>
我是相当新的TS,并尽我最大的努力学习绳索,所以任何阅读/视频观看也将是有帮助的!:)
1条答案
按热度按时间hmtdttj41#
您没有正确管理云函数的生命周期。正如doc中所解释的,您需要“通过返回一个JavaScript promise来解析执行异步处理的函数(也称为“后台函数”)”。
在你的例子中,你应该返回
runTransaction()
方法返回的Promise,如下所示:通过不正确地管理云函数的生命周期,您可能会产生云函数的一些“不稳定”行为(如您所提到的“事务不总是完成”)。
在后台触发的云函数中返回Promise(或值)向云函数平台指示它不应该终止函数,直到Promise已经实现并且避免在异步操作完成之前终止它。
因此,“事务并不总是完成”的原因很可能如下:有时您的云函数会在异步事务完成之前终止,原因如上所述。并且其他时间,云函数平台不立即终止函数,并且异步事务可以完成(即,有可能在云功能终止之前完成)。