用例:我有多个注释,每个注释都与一个标签绑定在一起。如果用户删除标签,则与该标签关联的所有注释都将绑定到默认标签。因此,要使其正常工作,我首先需要找出带有该标签的所有注释,用默认标签的ID替换其标签ID,最后删除选定的标签。所有这些都必须是原子的,因此需要Firestore Transaction
。
出现问题是因为我想通过触发get()
来query
多个文档。由于它是async
操作,因此整个交易目的消失了。我在文档中看到的示例仅涉及一个文档。
FirebaseConstants.getRootRef() // db reference
.runTransaction((Transaction.Function<Void>) transaction -> {
FirebaseConstants.getNotesRef() // Notes collection reference
.whereEqualTo("labelDetails.id", "<old_label_id>")
.get()
.addOnSuccessListener(snapshots -> {
ArrayList<String> listIds = new ArrayList<>();
for (DocumentSnapshot snap : snapshots.getDocuments()) {
listIds.add(snap.getId());
}
for (String id : listIds) {
FirebaseConstants.getNotesRef()
.document(id)
.update("labelDetails.id", "<default_label_id>");
}
// Labels collection reference
FirebaseConstants.getLabelsRef().document("<old_label_id>").delete();
});
return null;
})
.addOnSuccessListener(snapshots -> {
Toast.makeText(this, "transaction success", Toast.LENGTH_SHORT).show();
})
.addOnFailureListener(e -> {
Toast.makeText(this, "transaction failed", Toast.LENGTH_SHORT).show();
});
所以,我真的很想知道如何处理这种情况。我知道,我可以先get()
个匹配的ID,然后在get
的{{1}}内运行事务(或者甚至是批量写入,因为OnSuccessListener
已经完成),但这不能保证get()
和我的get()
之间的数据一致性吗?
因此,我想知道应该怎么做。如何使用update()
get
和update
多个文档?
答案 0 :(得分:1)
我可以先获取()匹配的id,然后在get的OnSuccessListener中运行事务(或者甚至是批写入,因为get()已经完成),但这不能保证get()和我之间的数据一致性update(),对吗?
是的,批量写入将解决您的问题。在这种情况下,不存在一致性问题,因为批处理写入是原子操作,或者所有操作都成功执行,或者都不应用任何操作。因此,您应该创建所需的查询,获取所有需要的文档,并将所有文档添加到一批更新操作中。最后,只需调用commit()
。请注意,每批次最多只能进行500次操作。如果您还需要更多,则应创建自己的机制来以500个操作的块来更新文档。
答案 1 :(得分:1)
Firestore 不不支持通过查询获取文档的客户端应用中的交易一致性。请注意,transaction
对象没有任何执行查询的方法。您只能执行单个文档的get()操作。
为了获得原子更新,必须对所有文档检索和更新使用提供的Transaction对象。您必须先阅读文档,然后才能编写文档(但是,如果您阅读文档,则不必编写文档)。
如果您需要处理来自查询结果的文档,则应在事务的外部中执行查询,并记住要在事务中使用的每个文档的ID。如果查询的结果在事务完成之前发生变化(例如,将添加或删除文档),则您的事务将处理“过时”的数据。
仅当您需要阅读文档的内容以便在编写文档之前做出决定时,事务才有意义。就您而言,您实际上并没有使用每个文档的内容来决定如何处理它。在这种情况下,批量写入就足够了。