Firebase Firestore事务多次触发,导致数据错误

Firebase Firestore事务多次触发,导致数据错误,firebase,transactions,google-cloud-functions,google-cloud-firestore,Firebase,Transactions,Google Cloud Functions,Google Cloud Firestore,因此,我有一个云函数,每次喜欢/不喜欢事务时都会触发它。此函数增加/减少likesCount。我已经使用firestore事务实现了同样的目的。我认为问题在于事务块中的代码被执行了多次,根据文档,这可能是正确的 但我的喜好计数在某些时候被错误地更新 return firestore.runTransaction(function (transaction) { return transaction.get(transRef).then(function (transDoc) {

因此,我有一个云函数,每次喜欢/不喜欢事务时都会触发它。此函数增加/减少likesCount。我已经使用firestore事务实现了同样的目的。我认为问题在于事务块中的代码被执行了多次,根据文档,这可能是正确的

但我的喜好计数在某些时候被错误地更新

 return firestore.runTransaction(function (transaction) {
        return transaction.get(transRef).then(function (transDoc) {
            let currentLikesCount = transDoc.get("likesCount");
            if (event.data && !event.data.previous) {
                newLikesCount = currentLikesCount == 0 || isNaN(currentLikesCount) ? 1 : transDoc.get("likesCount") + 1;
            } else {
                newLikesCount = currentLikesCount == 0 || isNaN(currentLikesCount) ? 0 : transDoc.get("likesCount") - 1;
            }
            transaction.update(transRef, { likesCount: newLikesCount });
        });
    });

任何人都有类似的经历

这可能与您从函数返回的内容有关,正如您所做的那样

return transaction.get(transRef).then(function (transDoc) { ... })
然后在该回调中返回另一个,但在最内部的嵌套回调中没有
return
。因此,它可能没有执行
事务。更新
。尝试删除前两个
return
关键字,并在
事务之前添加一个关键字。更新

firestore.runTransaction(function (transaction) {
        transaction.get(transRef).then(function (transDoc) {
            let currentLikesCount = transDoc.get("likesCount");
            if (event.data && !event.data.previous) {
                newLikesCount = currentLikesCount == 0 || isNaN(currentLikesCount) ? 1 : transDoc.get("likesCount") + 1;
            } else {
                newLikesCount = currentLikesCount == 0 || isNaN(currentLikesCount) ? 0 : transDoc.get("likesCount") - 1;
            }
            return transaction.update(transRef, { likesCount: newLikesCount });
        });
    });

超时

首先,检查您的云功能日志,查看是否收到任何
timeout
消息

Function execution took 60087 ms, finished with status: 'timeout'
如果是这样,请对函数进行排序,使其返回
Promise.resolve()
。和显示

Function execution took 344 ms, finished with status: 'ok'
幂等性

其次,编写数据,使函数是幂等的。函数运行时,向正在读取的文档写入一个值。然后,可以在再次运行函数之前检查该值是否存在


请参阅以确保函数只运行一次。

伙计们终于找到了这种意外行为的原因

如果您的应用程序将是流量密集型的,Firestore不适合维护计数器。他们在文件中提到了这一点。他们建议的解决方案是使用分布式计数器

许多实时应用程序都有充当计数器的文档。例如 你可能会在一篇文章中计算“喜欢”,或者计算某个特定项目的“最爱”

在CloudFireStore中,您只能更新单个文档一次 每秒,这对于某些高流量应用程序来说可能太低

我不相信这种方法,因为它对于一个简单的用例来说太复杂了,当我偶然发现下面的博客时

这些家伙使用了Firestore+Firebase的组合,从而消除了他们的弱点

Cloud Firestore方便地位于Firebase Realtime附近 数据库,两者易于使用、混合和匹配 在应用程序中。您可以自由选择将数据存储在两者中 如果项目符合您的需要,则为您的项目提供位置

因此,为什么不使用实时数据库的一个优点: 管理来自分布式客户端的快速数据流。哪一个是 在尝试聚合和计数数据库中的数据时出现的问题 消防商店


说Firestore是对实时数据库的升级(正如广告中所宣传的那样)是不正确的,但说Firestore是一个具有不同用途的不同数据库,两者可以而且应该在大规模应用程序中共存。这是我的想法。

但我的喜好计数在某些时间被错误地更新。
-你能详细说明这些特定时间是什么时候发生的,在什么情况下发生的吗?它是不规则的,并且是随机发生的。我应该返回transaction.update(transRef,{likescont:newlikescont})?您是否使用Firestore写入事件触发云函数?虽然Firestore处于测试阶段,但它的触发行为受到一些限制。看看这个答案:@BobSnyder。这是一个表演停止。我们不能只有幂等函数。对吗?我不知道何时(如果)取消这些限制。你可以问,因为这是一个异步云函数,我应该返回一个承诺来标记完成。请参见下文使用这些推荐的方法来管理函数的生命周期:通过返回JavaScript承诺来解析执行异步处理的函数(也称为“后台函数”)。是的,你是对的,我错过了这一部分。所以在这种情况下,您可能只需要去掉最初的两条
return
语句中的一条(没有在
事务之前添加另一个。更新
我担心的是,您的函数触发时间的不规则性使您难以确定根本原因。您知道这是否只是当一个事务在短时间内有很多喜欢/不喜欢的事,例如在2秒内有5个不喜欢和8个喜欢?我会尝试创建一些测试用例,看看是否可以在一致的基础上重现不正确的更新计数。我也是这么认为的。需要知道函数如何并行执行。函数在5000ms内以状态“ok”结束。“正如广告所示”你有参考资料吗?Firestore并不是RTDB的升级。如果你在谷歌官方文档中看到过这一点,我想知道。请参阅比较和。Cloud Firestore是Firebase用于移动应用开发的新旗舰数据库。它通过一个新的、更直观的数据模型改进了实时数据库的成功。Cloud Firestore还具有比实时数据库更丰富、更快的查询和更好的可扩展性。当它甚至不能处理与RTDB类似的写入时,它如何扩展?同一篇文章接着解释了每种方法的优点。没有看到“是升级”在任何地方,对不起。它肯定会像任何后续产品一样努力改进RTDBs限制,更加注重冗余和可靠性,在速度和简单性之间折衷一些微秒。所有这些都是合理的比较。@SharanMohandas所以您的意思是文档更新限制不适用于Realt吗ime数据库?RTDB允许的最大写入速率是多少?