首页 文章

Firebase检查是否存在值而不读取快照或尝试写入(对于唯一用户名)?

提问于
浏览
1

我已经坚持这个问题好几个小时了,所以任何帮助都表示赞赏 . 尝试使用Firebase制作Android应用程序以进行用户身份验证(简单登录电子邮件和密码)以及 unique 用户名 . 我的注册屏幕字段放在一个屏幕上,例如:

"Enter Username"
"Enter Email Address"
"Enter Password"

我很困惑如何查询数据库以检查用户名是否存在 without 读取数据库快照和 without 尝试将用户名写入数据库(因为这是在用户处于状态auth时发生的= = null ,所以在用户创建帐户之前的注册页面上,我想告知用户他的用户名是否被采用) .

我的意思是,这感觉它应该非常简单,只需要一个简单的查询Firebase并使用字符串并让Firebase返回 TrueFalse ,但经过几小时的谷歌搜索我什么都找不到 .

我通过将"read"设置为true来向公众提供名称及其UID的原因(我遵循了本指南,因此我的安全规则就像这样设置,以及我的数据库结构Firebase android : make username unique) .

这是我的规则,他们目前工作(我不喜欢读取设置为True的事实,这就是为什么我问这个问题):

{
  "rules": {
    "usernames": {
      ".read": true,
      "$username": {
        ".write": "auth !== null && !data.exists()"
      }
    },
    "users": {
        "$uid": {
            ".write": "auth !== null && auth.uid === $uid && !data.exists()",
            ".read": "auth !== null && auth.provider === 'password' && auth.uid === $uid",
            "username": {
              ".validate": "(!root.child('users').child(newData.val()).exists() || root.child('usernames').child(newData.val()).val() == $uid)"
     }
    }
   }
 }
}

这是我的数据:

{
  "usernames" : {
    "abcd" : "some-user-uid"
  },
  "users" : {
    "\"some-user-uid\"" : {
      "username" : "abcd"
    }
  }
}

谢谢!

1 回答

  • 1

    遗憾的是,没有办法测试数据是否存在而没有通过SDK实际下载 . 数据结构在这里将是至关重要的(建议阅读:NoSQL Data Structures,当优化和规模至关重要时,你不应该害怕denormalize一些数据 .

    一般来说,您应该保持数据结构良好,以便有效负载很小并获取它 . 如果您正在获取不能等待获取字节的内容(例如,游戏,奇怪的一次性管理员操作非常大的数据集等等),那么这里有一些合理的方法来模拟这个:

    Fetching a list of keys via the REST API

    在对REST API的调用中使用属性 shallow=true 将阻止加载大型数据集并仅返回该路径上的键 . 请注意,如果您存储了一百万条记录,它们仍然必须加载到服务器上的内存中(速度很慢),您仍然需要获取一百万个字符串(昂贵) .

    因此,在没有实际下载数据的情况下检查路径中数据是否存在的一种方法是调用路径,例如 https://<YOUR-FIREBASE-APP>.firebaseio.com/foo.json?shallow=true ,并检查是否返回任何键 .

    Creating a denormalized index you can query instead

    如果你真的需要从Firebase数据库中挤出一些额外的性能和速度(提示:你不需要这个,除非你每分钟运行数百万个查询,可能只用于游戏逻辑和类似),你可以双写你的记录(即非规范化)如下:

    /foo/data/$id/... data goes here...
    /foo/index/$id/true (just a boolean value)
    

    要进行双重写入,您可以使用update命令,并进行类似以下的编写(Android SDK示例):

    public void addRecord(Map<String, Object> data) {
       DatabaseReference db = FirebaseDatabase.getInstance().getReference();
    
       // create a new record id (a key)
       String key = db.child("foo").push().getKey();
    
       // construct the update map
       Map<String, Object> dualUpdates = new HashMap<>();
       dualUpdates.put("/data/" + key, /* data here */);
       dualUpdates.put("/index/" + key, true);
    
       // save the new record and the index at the same time
       db.child("foo").updateChildren(dualUpdates);
    }
    

    现在要确定是否存在记录,而不实际下载数据,我可以简单地查询 /foo/index/$id 并尝试 DataSnapshot.exists() ,代价是下载单个布尔值 .

相关问题