【问题标题】:Every document read in a transaction must also be written : Firestore Transaction Exception in android还必须写入事务中读取的每个文档:Android 中的 Firestore 事务异常
【发布时间】:2019-09-29 12:00:24
【问题描述】:

Firestore Transactions 给我以下错误:

原因:com.google.firebase.firestore.FirebaseFirestoreException:事务中读取的每个文档也必须写入。

这是一段代码:

   db.runTransaction(new Transaction.Function<Void>() {
        @Override
        public Void apply(Transaction transaction) throws FirebaseFirestoreException {


            DocumentReference docRef2 = db.collection("ABC").document(mMatchedUserId);

            DocumentReference ref3 = db.collection("XYZ").document(mCurrentUserId);
            DocumentReference ref4 = db.collection("XYZ").document(mMatchedUserId);


            DocumentSnapshot documentSnapshot2 = transaction.get(docRef2);

            if(documentSnapshot2.exists())
            {
                transaction.delete(docRef2);
                transaction.set(ref3, myMap1);
                transaction.set(ref4,myMap2);
            }

            return null;
        }
    }).addOnSuccessListener(new OnSuccessListener<Void>() {
        @Override
        public void onSuccess(Void aVoid) {
            Log.d(TAG, "Transaction success!");
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Log.w(TAG, "Transaction failure.", e);
        }
    });

如果我删除这个 if 条件 :if(documentSnapshot1.exists() &amp;&amp; documentSnapshot2.exists()) 则事务成功完成并且没有错误。

但设置此事务的主要点是 if 条件。请帮忙。

【问题讨论】:

    标签: java android firebase google-cloud-firestore


    【解决方案1】:

    您的代码中的问题在于,在您的事务中,您正在阅读两个文档:

    DocumentSnapshot documentSnapshot1 = transaction.get(docRef1);
    DocumentSnapshot documentSnapshot2 = transaction.get(docRef2);
    

    但你永远不会把它们写回去。正如我在您的代码中看到的那样,您只需要将它们进行删除操作,因此在这种情况下,请在事务之前而不是在事务内部阅读它们,您的问题就会得到解决。

    【讨论】:

    • 我已经编辑了问题以删除 transaction.get(docRef1),因为我不需要它。我在 if 条件中删除了 docRef2。 (delete() 是写操作。
    • 我正在事务中阅读它来解决这个问题。假设文档 C 在集合中。客户端 A 和 B 同时看到 C 并一起发起删除操作(以及另外 2 个相关操作)。我希望 A 和 B 中的任何一个都这样做,但不能同时进行。所以我必须在事务中检查它是否存在,然后才删除它。
    • 我明白,但你应该把数据写回去。不需要使用事务来删除某些数据,您可以简单地在引用上直接使用delete()。所以尽量隔离不属于事务的代码。请记住,交易绝对需要与服务器进行往返通信,以确保交易中的代码成功完成。所以读取数据,检查它是否是你需要的,然后写回来。
    • 我会注意到,您在事务中编写的每个文档也应该被事务读取(而不是在事务之外使用 DoucmentReference)。否则,如果其中一个在写入发生之前发生更改,您的文档最终可能会处于不一致的状态。
    猜你喜欢
    • 2020-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-25
    • 2018-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多