Firestore事务有条件更新?

时间:2018-05-19 18:46:40

标签: android firebase transactions google-cloud-firestore

我试图检查数据库中保存的值是否与用户选择匹配,如果确实如此,则更新它,否则不做任何事情。

我已尝试过以下操作,但获得例外:

  

引起:com.google.firebase.firestore.FirebaseFirestoreException:还必须写入事务中读取的每个文档。

这是我的代码:

//update toolbar titles if they match
final DocumentReference adminDocRef = mDbase.collection("admins").document(adminID);
mDbase.runTransaction(new Transaction.Function<Void>() {
    @Override
    public Void apply(@NonNull Transaction transaction) throws FirebaseFirestoreException {
        DocumentSnapshot adminSnapshot = transaction.get(adminDocRef);
        String toolbarTitle = adminSnapshot.getString("displayedUser");
        if (userName.equals(toolbarTitle)) {
            transaction.update(adminDocRef, "displayedUser", userName);
        }
        // Success
        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);
            }
        });  

交易是否有条件?如果不是,你会如何解决这个问题?似乎很傻,必须单独获取然后在其中嵌套更新。

非常感谢任何帮助。

谢谢!

3 个答案:

答案 0 :(得分:0)

来自answer

Alex来自documentation

交易可能因以下原因而失败:

  • 事务包含写操作后的读操作。在任何写操作之前必须始终进行读操作。 $.ajax({ type: "POST", url:"php/page.php", dataType:"json", success: function(data) { console.log(data); }, error:function (data) { console.log("Error"+data)} });
  • 该事务读取在事务之外修改的文档。在这种情况下,事务会自动再次运行。该交易重试次数有限。

在你的情况下,我会尝试

$array = new Array();

$ c = 0;

while(condition){
  $array[$c] = your_c_object
  $c++;
}

echo json_encode($array);

看看是否有效!

答案 1 :(得分:0)

因此,为了有条件地更新我的toolbarTitle,我必须以这种方式级联我的Firestore操作:

DocumentReference adminDocRef = mDbase.collection("admins").document(adminID);
    adminDocRef.get().addOnCompleteListener(activity, new OnCompleteListener<DocumentSnapshot>() {
        @Override
        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
            if (task.isSuccessful()) {
                DocumentSnapshot document = task.getResult();
                if (document.exists()) {
                    //assign document value to toolbarTitle
                    toolbarTitle = document.getString("displayedUser");
                    if (userName.equals(toolbarTitle)) {
                        DocumentReference adminDocRef = mDbase.collection("admins").document(adminID);
                        adminDocRef
                                .update("displayedUser", toolbarTitle)
                                .addOnSuccessListener(new OnSuccessListener<Void>() {
                                    @Override
                                    public void onSuccess(Void aVoid) {
                                        Log.d(TAG, "Displayed child has been updated");
                                    }
                                })
                                .addOnFailureListener(new OnFailureListener() {
                                    @Override
                                    public void onFailure(@NonNull Exception e) {
                                        Log.w(TAG, "Error: updating displayed child", e);
                                    }
                                });
                        Log.d(TAG, "DocumentSnapshot data: " + document.getData());
                    }

                } else {
                    Log.d(TAG, "No such document");
                }
            } else {
                Log.d(TAG, "get failed with ", task.getException());
            }
        }
    });

有点令人失望的是,我必须这样做,因为看起来它包含在交易中会更有意义。我希望他们允许在交易中使用条件行为。

答案 2 :(得分:0)

实际上,google有一个名为Tasks的类,您可以在其中使用它来同步Firestore调用。

因此,按照您的示例,您可以将其修复为以下内容:

try {
        DocumentSnapshot adminDocument = Tasks.await(adminDocRef.get());
        if (adminDocument.exists()) {
            String toolbarTitle = adminDocument.getString("displayedUser");
            if (userName.equals(toolbarTitle)) {
                Tasks.await(adminDocRef.update("displayedUser", userName));
                //Success
            }
        }
    } catch (ExecutionException e) {
        //Error
        e.printStackTrace();
    } catch (InterruptedException e) {
        //Error
        e.printStackTrace();
    }

这样,您就不需要侦听器了,同时这是有条件的更新。我知道这很晚了,但希望能对某人有所帮助。

[更新]: 请注意,不应在主线程上调用Tasks.await(...)调用,一种解决方案是使用AsyncTask