我正在尝试创建一个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" }
}
}
}
答案 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