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

时间:2017-10-19 16:21:16

标签: firebase nosql batch-processing google-cloud-functions google-cloud-firestore

我正在尝试创建一个WriteBatch来控制我的数据库中的一个动态引用。我的应用程序有一个简单的User-Follow-Post-Feed模型,我希望我的用户在他的Feed中查看他关注的所有用户的帖子。在研究Firebase示例(如Firefeed)和Stack Overflow上的大量帖子后,我正在做什么。

最佳想法是保留一个路径(在这种情况下为collection),其中我存储了我的用户应在其Feed中看到的帖子的Ids,这意味着要保持对每个帖子的控制和删除他关注/取消关注的所有用户的帖子。

我让Cloud functions以原子方式保留它,一切正常,但是当我尝试进行大量测试时,为用户添加了超过5000个帖子试图跟随他(看起来为了查看Cloud function需要多长时间,我看到批次限制为500次操作。所以我所做的就是将我的5000个id分成多个小列表,每个列表执行一个批处理,永远不会超过500个限制。

但即使这样做,我仍然会收到I can't do more than 500 operations in a single commit的错误,我不知道是否因为批次同时执行,或者为什么。我想也许我可以一个接一个地连接,并避免一次性执行它们。但我仍然有一些麻烦。这就是我提问的原因。

这是我的方法:

 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" }
            }
        }
    }

1 个答案:

答案 0 :(得分:7)

最后问题是因为我试图在一个事务中实现这个批处理操作,最终它也像批处理一样。这就是为什么即使我为每个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();
        });

它是在打字稿上写的,但你肯定会理解它: https://github.com/FrangSierra/firestore-cloud-functions-typescript/blob/master/functions/src/atomic-operations/index.ts