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

时间:2018-02-13 05:23:03

标签: firebase transactions google-cloud-functions google-cloud-firestore

所以我有一个云功能,每次交易被喜欢/不喜欢时都会触发。此函数递增/递减 likesCount 。我用firestore事务来实现同样的目的。我认为问题是Transaction块中的Code被多次执行,根据文档可能是正确的。

但我的喜欢计数在某些时候更新不正确。

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

任何人都有类似的经历

3 个答案:

答案 0 :(得分:4)

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

如果您的应用程序流量很大,Firestore不适合维护计数器。他们在文档中提到过它。他们建议的解决方案是使用分布式计数器。

  

许多实时应用程序都有充当计数器的文档。例如,   你可能会在某个帖子或某个特定项目的“收藏夹”中计算“喜欢”。

     

在Cloud Firestore中,您只能更新一次文档   每秒,这对于某些高流量应用来说可能太低了。

https://cloud.google.com/firestore/docs/solutions/counters

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

https://medium.com/evenbit/on-collision-course-with-cloud-firestore-7af26242bc2d

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

  

Cloud Firestore靠近Firebase Realtime   数据库,这两个很容易使用,混合和匹配   在申请中。您可以自由选择在两者中存储数据   适合您需求的项目地点。

     

那么,为什么不使用Realtime数据库来实现其优势之一:to   管理分布式客户端的快速数据流。哪一个   尝试聚合和计算数据时出现的问题   公司的FireStore。

说Firestore是对Realtime数据库的升级(因为它是广告)是不正确的,但是具有不同目的的不同数据库都可以并且应该在大规模应用程序中共存。这是我的想法。

答案 1 :(得分:1)

<强>超时

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

Function execution took 60087 ms, finished with status: 'timeout'

如果是这样,请整理您的函数,使其返回Promise.resolve()。并显示

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

<强>幂等性

其次,编写数据以使函数具有幂等性。当您的函数运行时,请将值写入您正在阅读的文档。然后,您可以在再次运行该函数之前检查该值是否存在。

请参阅this example以确保功能仅运行一次。

答案 2 :(得分:0)

它可能与你从函数返回的内容有关,就像你有

一样
return transaction.get(transRef).then(function (transDoc) { ... })

然后在该回调中再次返回,但在最内层嵌套的回调中没有return。所以它可能没有执行transaction.update。尝试删除前两个return关键字,并在transaction.update之前添加一个:

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