【问题标题】:Updating collection(s) in Firebase that are created w/Cloud Functions更新集合)在 Firebase 中使用 /Cloud Functions 创建
【发布时间】:2018-03-29 20:45:52
【问题描述】:

请注意,以下场景使用 Cloud Firestore

在我的云函数index.js 中,我有一个函数createUserAccount,它将新创建的用户添加到users 集合中,并为他们的电子邮件、照片、收藏夹设置字段(这是应用程序中的一个功能不需要详细说明),以及用户的其他一些不同的字段。该函数在成功完成以下代码sn-p时触发:

// The following method has been simplified to focus on the problem statement
public void createAccountWithEmailAndPassword(String username, String displayName,
                                              String someOtherImportantThing) {

    mFirebaseAuth.createUserWithEmailAndPassword(email, password)
                 .addOnCompleteListener(getActivity(), task -> {
                     if (task.isSuccessful()) {
                        Log.d(TAG, "createUserWithEmail:Success");
                        onSuccess.updateAccount(displayName, username);
                        updateUsernameProperty(username);
                        onBackPressed();
                    } else {
                          if (task.getException() != null) {
                              if (task.getException()
                                      .getMessage()
                                      .contains(EMAIL_EXISTS_ERROR)) {
                                  // Handle Email Exists Error
                              }
                          }
                          Log.w(TAG, "createUserWithEmail:failure",
                                    task.getException());
                    }
                });
     }

如您所见,当任务成功完成时,会调用几个方法:updateUsernameProperty(String username)updateAccount(String displayName, username)

updateAccount(String displayName) 获取用户选择的 displayName 并将其作为字段添加到用户帐户。 这不会更改用户集合 - 只会更改经过身份验证的帐户

updateUsernameProperty(String username) 获取用户选择的用户名并将此属性设置为用户文档中的字段。这是代码示例,因为它可能有助于理解我的问题:

private void updateUsernameProperty(String username) {
    DocumentReference docRef = mFirestore
                                  .collection(TABLE_USERS)
                                  .document(mFirebaseAuth.getUid());

    docRef.update(USERNAME_KEY, username)
            .addOnSuccessListener(aVoid -> Log.d(TAG, "Username DocumentSnapshot Successful"))
            .addOnFailureListener(e -> Log.e(TAG, "Error Updating Document: user/uid/username", e));
}

集合的典型路径是“users/{userId}/username”

问题:尝试更新用户文档中的用户名字段时,云函数createUserAccount 尚未完成创建/添加新用户文档到数据库(即异步问题) .

我考虑过使用 rxJava2 来帮助缓解这个问题,但我似乎无法理解如何做到这一点。任何帮助是极大的赞赏。

如果您有什么需要澄清的,我会尽力提供所需的信息。

【问题讨论】:

    标签: android firebase google-cloud-functions google-cloud-firestore


    【解决方案1】:

    如果我理解正确,你有以下流程:

    1. 您拨打createUserWithEmailAndPassword
    2. 云功能启动并将一些用户信息写入 Firestore
    3. 在本地,您尝试更新用户信息以包含 用户名。

    但第 2 步和第 3 步是竞争条件,因为当您在客户端上发布更新时,云功能可能不会完成。

    问题在于update() 调用取决于现有的文档。如果您在客户端代码和云函数中都使用 set() 调用和 merge 选项,您将避免这种情况。

    云功能

    function createUserDoc(userId, data) {
      var userRef = db.collection('users').doc(userId);
    
      // Set the user document, creating it if it does not exist
      // and merging with existing data if it does
      return userRef.set(data, { merge: true });
    }
    

    Android 代码

    public void updateUsername(userId, username) {
      Map<String, Object> data = new HashMap<>();
      data.put("username", username);
    
      db.collection("users").document(userId)
              .set(data, SetOptions.merge());
    }
    

    【讨论】:

    • 是的,这绝对是问题所在,而且可行!我能否就此征求您的意见:我的应用程序允许用户创建一个唯一的用户名并将此值存储在具有随机 UID 的集合“用户名”中。然后我添加两个字段,UID 与“用户”文档匹配的所有者和实际用户名的名称值。在“用户”文档中,我使用“用户名”集合中用户名的 UID 值更新“用户名”字段。当我需要在创建帐户时检查用户名是否可用时,这种方法是否有效?
    • @N.P 我不太了解您的情况,我认为如果您在 StackOverflow 上提出一个关于此的新问题(我很乐意回答),这将是最简单的方法
    • 我想知道是否有一种方法可以查询集合中的所有可用文档。 (例如,用户名集合中存在的所有文档仅存储唯一的用户名)。
    • @N.P 这个对话真的需要转移到它自己的问题上。
    猜你喜欢
    • 1970-01-01
    • 2020-01-12
    • 2018-01-02
    • 2020-05-31
    • 1970-01-01
    • 2020-09-30
    • 2018-01-19
    • 2023-03-31
    • 2019-04-16
    相关资源
    最近更新 更多