Условное обновление транзакций в Firestore? - PullRequest
0 голосов
/ 19 мая 2018

Я пытаюсь проверить, соответствует ли значение, сохраненное в базе данных, выбранному пользователем, если оно обновляется, в противном случае ничего не происходит.

Я пробовал следующее, нополучить исключение:

Причина: 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 голосов
/ 20 мая 2018

Таким образом, чтобы условно обновить заголовок моей панели инструментов, мне нужно было бы каскадировать операции 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());
            }
        }
    });

Немного разочаровывает, что мне придется делать это таким образом, так как кажется, чтоэто обернуло внутри транзакции будет иметь больше смысла.Я надеюсь, что они допускают условное поведение внутри транзакции.

0 голосов
/ 30 августа 2018

На самом деле, в 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.

0 голосов
/ 20 мая 2018

Существует аналогичный ответ из Alex , из документации

Транзакция может быть неудачной по следующим причинам:

  • Транзакция содержит операции чтения после операций записи.Операции чтения всегда должны предшествовать любым операциям записи.//not your case
  • Транзакция прочитала документ, который был изменен вне транзакции.В этом случае транзакция автоматически запускается снова.Транзакция повторяется конечное число раз.

В вашем случае я бы попробовал

if (userName.equals(toolbarTitle)) {
//transaction operations 
}

Проверьте, работает ли это!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...