Java 检查Firebase数据库中是否存在特定值

Java 检查Firebase数据库中是否存在特定值,java,android,firebase,firebase-realtime-database,Java,Android,Firebase,Firebase Realtime Database,我正在使用Firebaserealtime数据库制作一个Android应用程序。当新用户在我的应用程序上注册时,该用户的数据将保存在Firebase数据库中 用户必须提供以下详细信息才能注册: 全名 电子邮件 用户名 密码 数据库结构 每当新用户尝试注册时,我必须确保每个用户的用户名都是唯一的,因此我会检查数据库中是否存在用户输入的username 为此,我编写了以下方法: private boolean usernameExists(String username) { Datab

我正在使用
Firebase
realtime数据库制作一个Android应用程序。当新用户在我的应用程序上注册时,该用户的数据将保存在Firebase数据库中

用户必须提供以下详细信息才能注册:

  • 全名
  • 电子邮件
  • 用户名
  • 密码
  • 数据库结构

    每当新用户尝试注册时,我必须确保每个用户的用户名都是唯一的,因此我会检查数据库中是否存在用户输入的
    username

    为此,我编写了以下方法:

    private boolean usernameExists(String username) {
         DatabaseReference fdbRefer = FirebaseDatabase.getInstance().getReference("Users/"+username);
         return (fdbRefer != null);
    }
    
    这个方法背后的逻辑是,如果
    getReference
    方法找不到对指定路径的引用,它将返回null,以便我可以返回
    fdbRefer
    是否为
    null
    。如果
    fdbRefer
    null
    ,则表示数据库中不存在
    username

    问题 此方法的问题是,无论输入的
    用户名是否存在于数据库中,它总是返回
    true
    。这让我相信
    fdbRefer
    永远不会
    null

    这就引出了我的问题

    问题:
    当在
    firebase
    数据库中找不到指定路径时,
    getReference
    方法返回什么?检查
    用户名是否已存在于数据库中的正确方法是什么?

    您可以使用orderBy查询来检查用户名是否存在,而不是检查引用是否存在已经

    orderByChild('username')。如果某些数据已经存在,则equalTo(username)查询将返回数据,否则它将返回null。

    像这样检查它

        fdbRefer.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
    if(dataSnapshot.exist() {
    //username exist
    }
    else {
    //username doesn't exist
    }
    }
    });
    
    试试这个:

    DatabaseReference ref=FirebaseDatabase.getInstance().getReference().child("Users");
    ref.orderByChild("username").equalTo(Nick123).addValueEventListener(new ValueEventListener(){
      @Override
      public void onDataChange(DataSnapshot dataSnapshot){
          if(dataSnapshot.exist() {
             //username exist
              }
            }
    
    您必须使用
    orderbychild
    equalto
    检查值是否存在。 如果您不使用
    orderbychild
    equalto
    ,那么它只会检查
    username
    子节点是否存在并且不关心值

    这个
    orderByChild(“username”).equalTo(Nick123)
    就像是说:

    WHERE username=Nick123
    

    要检查用户是否存在,请使用以下代码:

    DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
    DatabaseReference userNameRef = rootRef.child("Users").child("Nick123");
    ValueEventListener eventListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            if(!dataSnapshot.exists()) {
                //create new user
            }
        }
    
        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
        }
    };
    userNameRef.addListenerForSingleValueEvent(eventListener);
    
    您还可以使用查询来实现如下相同的功能:

    DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
    Query query = rootRef.child("Users").orderByChild("userName").equalTo("Nick123");
    query.addValueEventListener(/* ... */);
    
    这是另一种在整个
    用户
    节点中循环的方法,而不仅仅是直接引用单个用户。当您使用
    uid
    而不是用户名作为用户之间的唯一标识符时(如您现在所做的),更可能使用此选项。因此,如果您的数据库结构可能与此类似:

    Firebase-root
       |
       --- Users
            |
            --- uid
                 |
                 --- userName: "Test User"
                 |
                 --- emailAddress: "user@email.com"
    
    第二种解决方案是推荐的解决方案

    还有另一个解决方案,其中包括创建另一个名为
    用户名的节点,在该节点中,您只能保存唯一的用户名。请参阅以下相应的安全规则:

    "Users": {
      "$uid": {
        ".write": "auth !== null && auth.uid === $uid",
        ".read": "auth !== null && auth.provider === 'password'",
        "userName": {
          ".validate": "
            !root.child('userNames').child(newData.val()).exists() ||
            root.child('userNames').child(newData.val()).val() == $uid"
        }
      }
    }
    

    但是,由于在本例中,您的用户名已经是节点的名称,因此我建议您继续使用第一个名称。

    由于您已经找到了问题的解决方案,我将尝试解释代码不起作用的原因

    您可能会认为,在上述语句中,如果数据库中不存在“Users/”+username,则fdbRefer
    将为null。
    但实际上,该语句只存储
    getReference()
    中指定字段的路径。所以当你检查
    fdbRef=null
    ,它始终为真,因为
    fdbRefer
    将保存类似以下内容的值https://.firebase.com/Users/Nick123.非常适合我

    DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
            Query query = reference
                    .child(getString(R.string.dbname_users))
                    .orderByChild("username")
                    .equalTo(username);
            query.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    if(dataSnapshot.getChildrenCount()>0) {
                        //username found
    
                    }else{
                        // username not found
                    }
    
                }
                @Override
                public void onCancelled(DatabaseError databaseError) {
    
                }
            });
    

    请参见这两种方法之间的差异。使用第一种解决方案将帮助您节省带宽。您能否解释一下(!dataSnapshot.exists())
    的作用是什么?
    dataSnapshot
    对象表示以下位置的快照:
    Firebase root->Users->Nick123
    。最好的解决方案是直接在
    dataSnapshot
    上使用
    exists()
    方法检查是否存在。当您使用查询时,您在整个对象中循环,这意味着浪费带宽。我还给您提供了查询解决方案,也许您将来会需要。@RedM第一个解决方案是使用直接指向特定用户的引用,而第二个解决方案是使用搜索整个对象以找到相应用户的查询。@MehulTank在这种情况下,您应该使用Peter的答案。
    DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
            Query query = reference
                    .child(getString(R.string.dbname_users))
                    .orderByChild("username")
                    .equalTo(username);
            query.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    if(dataSnapshot.getChildrenCount()>0) {
                        //username found
    
                    }else{
                        // username not found
                    }
    
                }
                @Override
                public void onCancelled(DatabaseError databaseError) {
    
                }
            });