Firebase 使用带有云功能的计数器时,防止写入Firestore文档的时间超过1秒 背景:

Firebase 使用带有云功能的计数器时,防止写入Firestore文档的时间超过1秒 背景:,firebase,google-cloud-firestore,google-cloud-functions,Firebase,Google Cloud Firestore,Google Cloud Functions,我有一个Firestore数据库和一个用户集合。每个用户都是一个包含联系人集合的文档。该集合中的每个文档都是一个联系人 由于firestore没有针对所有文档的“计数”功能,并且由于我不想读取所有联系人来计算用户拥有的联系人数量,因此当添加或删除联系人时,我会触发云函数,从而增加或减少用户文档中的numberOfContacts。为了使函数幂等,它必须进行多次读取和写入,以防止在同一文档中多次调用计数器时计数器多次递增。这意味着我需要有一个我已经处理过的EventID的不同集合,这样我就不会复制

我有一个Firestore数据库和一个用户集合。每个用户都是一个包含联系人集合的文档。该集合中的每个文档都是一个联系人

由于firestore没有针对所有文档的“计数”功能,并且由于我不想读取所有联系人来计算用户拥有的联系人数量,因此当添加或删除联系人时,我会触发云函数,从而增加或减少用户文档中的numberOfContacts。为了使函数幂等,它必须进行多次读取和写入,以防止在同一文档中多次调用计数器时计数器多次递增。这意味着我需要有一个我已经处理过的EventID的不同集合,这样我就不会复制它。这需要我每月运行一次另一个函数,以检查每个用户是否删除所有此类文档(这需要大量的读取和写入)


问题 现在的挑战是用户可以导入他/她的联系人。因此,如果一个用户导入10000个联系人,此功能将连续快速启动10000次

我如何防止这种情况


目前的做法: 现在,我正在联系人文档中添加一个字段,该字段指示添加是导入的一部分。这将使云函数不递增

我在一个事务中一次从客户机499个联系人执行该操作,这也会在第500次写入时增加计数。这样,如果某件事情中途失败,计数保持一致

这真的是最好的方法吗?仅仅拥有一个可用联系人的数量似乎很复杂。每次一个联系人发生变化时,我都要进行多次读写操作,而且我每个月都要运行清理功能


我一直在想一定有更简单的方法

对于那些好奇的人来说,我采取的方法似乎是最好的方法

我在联系人文档中添加了一个字段,指示添加是导入的一部分(bulkAdd=true)。这将使云函数不递增


我有另一个云函数,一次添加200个联系人(我做FieldValue.timestamp,这算作另一次写入,所以是400次写入)。我在批处理中执行此操作,批处理中的第401次写入是增量计数。这样,我就可以批量导入联系人,而不必用写操作轰炸单个文档

增量问题

存在重复的安全操作,如
FieldValue.arrayUnion()
FieldValue.arrayRemove()
。我在这里写了一些关于这种方法的内容:

通过这种方法,您可以使您的用户文档包含一个带有联系人ID的特殊数组字段。将联系人添加到子集合并触发您的功能后,可以将联系人的id写入此字段。如果一个联系人触发该功能两次或多次,则只有一个实例写入主用户文档。但实际大小可以在客户端获取,也可以在用户文档更新时触发另一个函数。这比使用EventID要简单一些

导入10k+联系人时出现问题

这有点哲学性。 如果我得到它,问题是一个用户执行10k写入。除了这些10k写操作之外,还会触发10k函数,这些函数对主控文档执行额外的10k写操作(如果它们使用EventID文档,则读取量相同)

您可以创建一个特殊的子集合,仅用于将多个联系人导入数据库。客户端将创建一个包含10k联系人字段的大文档,而不是将10k文档写入数据库,这将触发云功能。上述函数将全部读取,使必要的10k联系人写入+1写入主文档和所有阵列。您只需要考虑如何防止10k调用的函数写入(添加一个特殊的元数据字段,如bulkAdd)


这只是一个意见。

谢谢,道格。实际上,我不想做分布式碎片,因为我的正常用例没有太多的写操作。这只是在导入联系人时,所以我希望保持正常用例的简单性和读取速度。我有一个可行的解决方案,这让我很恼火,因为总的来说,“用户X有多少联系人”这个简单的问题非常复杂。不可能为某些调用暂时禁用某个函数。要使用的数据必须位于已更改的文档中。幂等性也必然增加函数必须执行的工作量。我认为没有一条简单的出路。