Как добавить новые поля в Firestore Document из двух разных источников одновременно? - PullRequest
0 голосов
/ 23 апреля 2020

Когда новый пользователь регистрируется в моем приложении, используя firebase-authentication пользовательский вход, используя электронную почту и пароль, мне необходимо обновить эти данные в моем пожарном депо. Но у Firebase есть только FirebaseAuth.createUserWithEmailAndPassword(email, password) для создания новой учетной записи, и поэтому я не могу обновить username моего пользователя одновременно.

Для обновления электронной почты в Firestore я использую облачные функции Firebase. Вот код:

export const onNewUserJoined = functions.auth.user().onCreate((user) => {

    //const newUserDisplayName = user.displayName //CAN'T USE THIS. REASON is BELOW
    const newUserUID = user.uid
    const newUserEmail = user.email
    const timeCreated = Date.now()

    console.log(`${newUserUID} has joined.`)

    return admin.firestore().collection('Agent').doc(`${newUserUID}`).set({"E-Mail": newUserEmail, "Time": timeCreated})               
})     

Хорошо, отлично, теперь я успешно обновил E-Mail и время, созданное в Firestore.

Но следующая задача - мне нужно обновить имя пользователя в тот же документ Firestore. Я делаю это сразу после createUserWithEmailAndPassword(), например:

 DocumentReference dDocRef = FirebaseFirestore.getInstance().document(documentPath);
 Map<String, Object> updateUsernameAndPhone = new HashMap<>();
 updateUsernameAndPhone.put("username", username);
 updateUsernameAndPhone.put("phoneData", phoneModel);
 dDocRef.update(updateUsernameAndPhone).addOnSuccessListener(new OnSuccessListener<Void>() {
     @Override
     public void onSuccess(Void aVoid) {
         Toast.makeText(getApplicationContext(), "Data successfully stored in Firestore", Toast.LENGTH_SHORT).show();
        }
    }).addOnFailureListener(new OnFailureListener() {
    @Override
     public void onFailure(@NonNull Exception e) {
         Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
         }
    });

Теперь все зависит от того, кто действует первым, облачная функция или устройство пользователя.

Если сначала действуют облачные функции, то проблем нет. И имя пользователя, и phoneModel успешно обновляются в документе. Нет проблем.

Но в случае, если сначала телефон работает, то я получаю следующую ошибку:

enter image description here

Поскольку эта ошибка произошла, имя пользователя отсутствует в документе, и только электронная почта и timeCreated находятся в документе, обновленном облачной функцией, которая запоздала с созданием документа, чтобы пользовательское устройство могло легко обновить имя пользователя.

I CAN ' T использует .SET вместо .update() в моем приложении, потому что, если я использую .set() и облачные функции, сначала создайте поля email и timeCreated. Затем устройство удалит их и поместит имя пользователя и phoneModel.

Так как я могу это сделать?

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

Раньше я использовал .update(), когда мои данные хранились в базе данных реального времени и использовались для создания дочернего элемента, даже если путь не существовал. Но похоже, что Firestore не будет обновляться, если поле не существует.

Есть какое-нибудь решение для этого?

Я пытался, как сказал @DougStevenson, и вот мой код:

final String newUserUID = Objects.requireNonNull(signUpAuth.getCurrentUser()).getUid();

final String documentPath = "Agent/" + newUserUID;

FirebaseFirestore fFirestoreRef = FirebaseFirestore.getInstance();
final DocumentReference dDocRef = fFirestoreRef.document(documentPath);

fFirestoreRef.runTransaction(new Transaction.Function<Void>() {
@Nullable
@Override
    public Void apply(@NonNull Transaction transaction) throws 
    FirebaseFirestoreException {
    DocumentSnapshot documentSnapshot = transaction.get(dDocRef);
    transaction.update(dDocRef, "username", username);
    transaction.update(dDocRef, "phoneData", phoneModel);
    return null;
  }
}).addOnSuccessListener(new OnSuccessListener<Void>() {
 @Override
 public void onSuccess(Void aVoid) {
 Toast.makeText(getApplicationContext(), "Data updated in Firestore . . .", Toast.LENGTH_SHORT).show();
  }
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
    Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
       }
   });

Но не повезло. Это все еще дает мне ошибку: Cannot update a document which does not exist.

1 Ответ

0 голосов
/ 23 апреля 2020

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

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