【问题标题】:How to read child nodes without mentioning parent node in firebase database within android studio?如何在不提及android studio中firebase数据库中的父节点的情况下读取子节点?
【发布时间】:2020-11-30 09:46:13
【问题描述】:

我正在使用 firebase 实时数据库制作一个 android 应用程序。我的规则结构如下:

{
// Allow anyone to read data, but only authenticated content owners can
// make changes to their data

  "rules": {
    "Users": {
      "$uid": {
        ".read": true,
        // or ".read": "auth.uid != null" for only authenticated users
        ".write": "auth.uid == $uid"
      }
    }
  }
}

这意味着用户应该以经过身份验证的用户身份登录才能写入一些数据。但是,阅读不需要登录。

现在我需要忽略用户的 uid 以免费访问其他用户(即无需登录)。

这是我目前用来读取数据的java代码。

final Intent k = getIntent();
        final String school = Objects.requireNonNull(k.getExtras()).getString("School");
        final Intent i = getIntent();
        final String roll = Objects.requireNonNull(i.getExtras()).getString("Roll");
 myRef = myfire.getReference("Users")
.child("GcZoeK7JIbNWVOog6ZjUPiBfxwn2")// **I have problem here.**
.child(school).child(roll);
        myRef.child("basic").addValueEventListener(new ValueEventListener() {

            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                String name = (String) dataSnapshot.child("fb01name").getValue().toString();

                String number = (String) dataSnapshot.child("fb04roll").getValue().toString();

                if(name == null){

                    Toast.makeText(getApplicationContext(),"Invalid",Toast.LENGTH_SHORT).show();
                }

                basic model = new basic(name,number);
                tvName.setText(name);

                tvRoll.setText(number);



            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {

            }

        });

我无法决定要写什么而不是第一个孩子在没有登录的情况下读取任何数据。

.child("GcZoeK7JIbNWVOog6ZjUPiBfxwn2")

请指导我如何忽略这个孩子?任何帮助将不胜感激。

编辑 @Abdullah Z Khan 的建议“尽量避免使用深度嵌套的孩子”进一步让我深入了解了这个问题。我更改了我的代码,如下所示:

 myfire = FirebaseDatabase.getInstance();
        final Intent k = getIntent();
        final String school = Objects.requireNonNull(k.getExtras()).getString("School");
        final Intent i = getIntent();
        final String roll = Objects.requireNonNull(i.getExtras()).getString("Roll");
        
//--------------------the trick----------------

        if (school.equals("224613")){
             tvSchool.setText("GcZoeK7JIbNWVOog6ZjUPiBfxwn2");
        }else if (school.equals("224614")){
             tvSchool.setText("uQx5jDVRp9PV3QpM2FBU6HPq5SJ3");
        }
        final String uid = tvSchool.getText().toString();
//---------------------------------------------------
        myRef = myfire.getReference("Users").child(uid).child(roll);
        myRef.child("basic").addValueEventListener(new ValueEventListener() {

            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                String name = (String) dataSnapshot.child("fb01name").getValue().toString();

                String number = (String) dataSnapshot.child("fb04roll").getValue().toString();

                if(name == null){

                    Toast.makeText(getApplicationContext(),"Invalid",Toast.LENGTH_SHORT).show();
                }

                basic model = new basic(name,number);
                tvName.setText(name);

                tvRoll.setText(number);



            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {

            }

        });

虽然这个PLAN B让我暂时松了口气,但问题还是没有回答。因为每次加入应用我都要写用户的uid代码 (并且必须一次又一次地更新和发布应用程序。等待更好的解决方案。

【问题讨论】:

  • 您想从哪个用户读取数据...如果您想忽略该用户.. 那么您想读取哪个basic 节点的底层子节点?

标签: java android firebase-realtime-database firebase-security


【解决方案1】:

编辑:>>>标记的行中添加值以供理解

根据给出的,这是您的数据库结构:

{
    "uid": {
        "schoolId": {
            "roll": {

            }
        }
    }
}

因为它嵌套太多(我建议完全不同的层次结构),所以没有 简单的方式来访问具有未知父母的孩子。但是,如果您可以将数据库结构更改为:

{
    >>> "224614":"GcZoeK7JIbNWVOog6ZjUPiBfxwn2",
    "schoolId2":"uid2",
    >>> "GcZoeK7JIbNWVOog6ZjUPiBfxwn2": {
        "224614": {
            "roll": {

            }
        }
    }
}

您将获得一个 uid 查找表。然后,您可以使用它来到达节点。请记住,这不是您所问问题的直接答案,即如何在不知道父级的情况下获取嵌套节点(不是值),但在这里您可以动态访问所需学校的 uid,假设每所学校都有一个父母。

之后,嵌套你的监听器:

myRef = myfire.getReference("Users");
myRef.child(school).addValueEventListener(new ValueEventListener() {

            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                if  (dataSnapshot.exists()) {
                    String uid=dataSnapshot.getValue(String.class);
                    myRef.child(uid)// **I have problem here.**
                    .child(school).child(roll);
                            myRef.child("basic").addValueEventListener(new ValueEventListener() {

                                @Override
                                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                                    String name = (String) dataSnapshot.child("fb01name").getValue().toString();

                                    String number = (String) dataSnapshot.child("fb04roll").getValue().toString();

                                    if(name == null){

                                        Toast.makeText(getApplicationContext(),"Invalid",Toast.LENGTH_SHORT).show();
                                    }

                                    basic model = new basic(name,number);
                                    tvName.setText(name);

                                    tvRoll.setText(number);



                                }

                                @Override
                                public void onCancelled(@NonNull DatabaseError error) {

                                }

                            });
                }

            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {

            }

        });

在实践中,尽量避免使用深度嵌套的子节点,而是使用对其他节点的引用。

我希望这会有所帮助!

【讨论】:

  • 查看我给出的最后一段代码和我给出的数据库结构。理论上,每次创建一所学校时,你都会做两件事。 1:在“用户”中创建一个节点,其中节点名称/键=学校,节点值=与该学校关联的uid。然后你按照我提供的代码,填充你需要的变量
  • 注意:我回答的目的是帮助代码从数据库中的另一个节点中查找 uid,因此您无需对其进行硬编码。第一个 onDataChange 将为您提供学校的 uid(前提是您按照我的建议在数据库中添加了额外的节点)。
  • Users 节点中,以及其他 uid。我会用你的价值观更新答案。
  • Firebase 控制台 > 实时数据库 > 规则 这将帮助您提供数据库的结构、树层次结构,因为从您的图像中我无法判断“用户”是否存在于根节点或子节点。
  • 因为我不知道您的完整层次结构,所以我添加了该部分,以便您可以自己将其与现有规则集合并。例如,我不知道用户是在第二个节点还是第三个节点,所以你必须自己应用适当的级联。
【解决方案2】:

这个怎么样:

final Intent k = getIntent();
    final String school = Objects.requireNonNull(k.getExtras()).getString("School");
    final Intent i = getIntent();
    final String roll = Objects.requireNonNull(i.getExtras()).getString("Roll");
    myRef = myfire.getReference("Users")
    
    myRef.addValueEventListener(new ValueEventListener() {

        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            String name = (String) dataSnapshot.child(school).child(roll).child("basic").child("fb01name").getValue().toString();

            String number = (String) dataSnapshot.child(school).child(roll).child("basic").child("fb04roll").getValue().toString();

            if(name == null){

                Toast.makeText(getApplicationContext(),"Invalid",Toast.LENGTH_SHORT).show();
            }

            basic model = new basic(name,number);
            tvName.setText(name);

            tvRoll.setText(number);



        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {

        }

    });

【讨论】:

  • 从这一行 :myfire.getReference("Users") 获取快照中的所有 uid,然后通过调用适当的 child() 从快照中获取所需的子项。你得到了什么错误?也许可以解决。
  • 好吧,因为您是唯一可以访问您的代码的人,您需要进行一些调试并稍微调整代码以使其适合您。但我很确定这是解决这个问题的方法
  • 但这不是我的答案中的代码。我的代码有什么问题?为什么不调试它并找出它返回的值。因为它没有崩溃,这意味着它正在获取一些东西。
【解决方案3】:

好吧,我不知道我是否理解您的问题,但是如果您尝试读取所有节点的子节点而不指定它们,您可以尝试执行以下代码:(我没有测试它,我只是改变了你的样本)

    myRef = myfire.getReference("Users");
    myRef.addValueEventListener(new ValueEventListener() {

        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

            for (DataSnapshot keySnap : dataSnapshot.getChildren()) {
                for (DataSnapshot schoolSnap : keySnap.getChildren()) {
                    for (DataSnapshot rollSnap : schoolSnap.getChildren()) {
                        String mRollSnap = rollSnap.getKey();

                        String name = mRollSnap.child("basic").child("fb01name").getValue().toString();
                        String number = (String) mRollSnap.child("basic").child("fb04roll").getValue().toString();
                        if(name == null){
                            Toast.makeText(getApplicationContext(),"Invalid",Toast.LENGTH_SHORT).show();
                        }
                        basic model = new basic(name,number);
                        tvName.setText(name);
                        tvRoll.setText(number);

                    }
                }
            }
        }
        @Override
        public void onCancelled(@NonNull DatabaseError error) { }
    });

【讨论】:

    猜你喜欢
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    • 2019-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多