首页 > 解决方案 > 使用 Firestore 事务更新多个文档

问题描述

用例:我有多个笔记,每个笔记都绑定到一个标签。如果用户删除标签,则与该标签关联的所有注释都与默认标签相关联。所以要让它工作,我首先需要找出所有带有该标签的笔记,用默认标签的 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's中运行事务OnSuccessListener(甚至是批量写入,因为get()已经完成),但这并不能保证get()和 my之间的数据一致性update(),是吗?

因此,我想知道应该如何做到这一点。如何getupdate多个文件使用Transaction

标签: javaandroidfirebasegoogle-cloud-firestoretransactions

解决方案


Firestore 不支持通过查询获取文档的客户端应用程序中的事务一致性。请注意,该transaction对象没有任何方法来执行查询。您只能执行单个文档 get() 操作。

为了获得原子更新,您必须使用提供的Transaction对象进行所有文档检索和更新。您必须先阅读文档才能编写它(但如果您阅读文档,则不必编写它)。

如果您需要处理来自查询结果的文档,您应该在事务之外执行查询并记住每个文档的 ID 以在事务中使用。如果在事务完成之前查询的结果会发生变化(例如,将添加或删除文档),那么您的事务将处理“过时”的数据。

仅当您需要阅读文档的内容以便在编写之前做出决定时,事务才有意义。在您的情况下,您实际上并没有使用每个文档的内容来决定如何处理它。在这种情况下,批量写入就足够了。


推荐阅读