在Firestore数据库中一次执行超过500个操作

5
我正在尝试创建一个WriteBatch,来控制我的数据库中动态引用之一。我的应用程序具有简单的User-Follow-Post-Feed模型,我希望用户在其Feed中看到他关注的所有用户的帖子。通过Firebase示例(如Firefeed)和Stack Overflow上的许多帖子研究后,我做了以下操作。
最佳方法是保留路径(在本例中为collection),其中存储用户应在其Feed中看到的帖子的Ids。这意味着需要控制关注/取消关注的所有用户的每篇帖子的复制和删除。
我使用Cloud functions以原子方式保持此状态,并且一切正常运行。但是,当我尝试进行大规模测试时,向用户添加超过5000个帖子并试图关注他(寻找查看Cloud function将花费多长时间),我发现batch有500个操作的限制。因此,我将我的5000个ID拆分为多个小列表,并为每个列表执行一个batch,从未超过500个限制。
但即使以这种方式执行,我仍然会收到错误消息,我无法在单个提交中执行超过500个操作,我不知道是否因为批次同时执行,或者其他原因。我认为也许可以将它们连接在一起,并避免同时执行它们。但我仍然遇到了一些问题,这就是我的问题所在。
以下是我的方法:
 fun updateFeedAfterUserfollow(postIds: QuerySnapshot, userId: String) {
        //If there is no posts from the followed user, return
        if (postIds.isEmpty) return
        val listOfPostsId = postIds.map { it.id }
        val mapOfInfo = postIds.map { it.id to it.toObject(PublicUserData::class.java) }.toMap()

        //Get User ref
        val ref = firestore.collection(PRIVATE_USER_DATA).document(userId).collection(FEED)
        //Split the list in multiple list to avoid the max 500 operations per batch
        val idsPartition = Lists.partition(listOfPostsId, 400)

        //Create a batch with max 400 operations and execute it until the whole list have been updated
        idsPartition.forEach { Ids ->
            val batch = firestore.batch().also { batch ->
                Ids.forEach { id -> batch.set(ref.document(id), mapOfInfo[id]!!) }
            }
            batch.commit().addOnCompleteListener {
                if (it.isSuccessful)
                    Grove.d { "Commit updated successfully" }
                else Grove.d { "Commit fail" }
            }
        }
    }

你收到了什么错误信息? - Sam Stern
你的最终解决方案是什么? - Ryann Galea
嗨Francisco,我想知道你能否帮助我。我正在使用Firestore做类似于用户-关注-帖子-动态的东西,我想问你一个问题。如果一个用户有5000个粉丝并发布了一篇帖子,你是为每个粉丝生成该帖子的索引还是为每个粉丝创建该帖子的副本。谢谢! - Giovanny Piñeros
我会为每个用户添加索引。不需要添加整个帖子副本,因为帖子可以多次编辑,而ID则不能。请查看我的一个存储库,其中我使用云函数解决此类问题 https://github.com/FrangSierra/firestore-cloud-functions-typescript - Francisco Durdin Garcia
1个回答

10
最后问题是由于我试图在事务内实现这批操作,而事务最终也像一批操作一样。这就是为什么即使我为每400个引用生成批次,这些实例也是在事务内创建的,并且它被计算为一个超过500限制的大事务。
我做了一些更改,并在我的GitHub存储库上实施了这些更改。
//Generate the right amount of batches
    const batches = _.chunk(updateReferences, MAX_BATCH_SIZE)
        .map(dataRefs => {
            const writeBatch = firestoreInstance.batch();
            dataRefs.forEach(ref => {
                writeBatch.update(ref, 'author', newAuthor);
            });
            return writeBatch.commit();
        });

这是用TypeScript编写的,但你肯定能理解的: https://github.com/FrangSierra/firestore-cloud-functions-typescript/blob/master/functions/src/atomic-operations/index.ts

有时为150个参考文献生成批次会出现“超过截止时间”的错误。您有什么建议吗? - Akshay komarla
你是同时抛出它们还是一个接一个地抛出? - Francisco Durdin Garcia
在这个5000项的示例中,Francisco函数是完成500个批次提交,然后继续下一个500个吗?还是同时执行10个批次(每个500个,因此一次5000个)? - siefix
如果我们使用"await writeBatch.commit();"而不是"return writeBatch.commit();",它可能不会受到任何限制,对吧? - Ayyappa
await writeBatch.commit() 仍然会受到限制。这是因为它在一个 map 和 Promise.all 中。你需要将它放在一个带有 await 的 for 循环中(不是 foreach,因为 promises 不像你想象的那样工作)。这样做可以确保它是一个接一个地执行的。 - Daniel Hair

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接