【问题标题】:Organizing firebase data组织 Firebase 数据
【发布时间】:2017-09-19 20:10:57
【问题描述】:

我正在使用 Firebase 身份验证和 Firebase 数据库来存储学生的个人资料和学生报告。

当用户注册时,他们输入电子邮件、密码、学校名称、学年、学校纪律。我使用电子邮件和密码进行身份验证,但其余信息以唯一 ID 存储在数据库中,如下所示:

对于报告,每个学生可以输入许多条目,每个条目都有其唯一的 ID,如下所示:

这是我的问题:

  1. 一旦学生登录,我如何才能找到他们的个人资料信息,因为父母是唯一的 ID。换句话说,有没有办法在数据库中搜索学生的电子邮件(例如,图像中的 mido4@hotmail.com)并从中获取学生的姓名(在本例中为 Emina Osman)?

  2. 获得学生姓名后,如何搜索学生在数据库中保存的所有条目?对于学生拥有的每个条目,都会保存学生姓名。

  3. 不确定我设置数据库的方式是否理想,有没有更好的方法?

感谢您的宝贵时间!任何帮助将非常感激!

【问题讨论】:

    标签: java firebase firebase-realtime-database firebase-authentication


    【解决方案1】:
    1. 是的,是的。实现这一点的最简单方法是稍微改变你的数据库结构。因此,我建议您使用电子邮件地址,而不是使用push() 方法生成的推送键作为唯一标识符。它也很独特且易于使用。好处是,这允许您在数据库中搜索该特定电子邮件。您的数据库结构应如下所示:

      flashscreen-1d252
           |
           --- Users
                 |
                 --- mido4@hotmail,com
                 |      |
                 |      --- //User Details
                 |  
                 --- mido5@hotmail,com
                        |
                        --- //User Details
      

    请注意,Firebase 不允许在键中使用符号 .(点)。正如您可能看到的,我已经用,(逗号)更改了. 点。我使用以下方法实现了这一点:

    String encodeUserEmail(String userEmail) {
        return userEmail.replace(".", ",");
    }
    

    要搜索用户并获取名称,只需在 Users 节点上添加一个侦听器,如下所示:

    DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
    DatabaseReference userRef = rootRef.child("Users").child("mido4@hotmail,com");
    ValueEventListener eventListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            if(dataSnapshot.exists()) {
                String firstName = dataSnapshot.child("firstname").getValue(String.class);
                String lastName = dataSnapshot.child("lastname").getValue(String.class);
                Log.d("TAG", firstName + " " + lastName);
            }
        }
    
        @Override
        public void onCancelled(DatabaseError databaseError) {}
    };
    usersRef.addListenerForSingleValueEvent(eventListener);
    

    输出将是:Emina Osman

    1. 您必须搜索电子邮件地址而不是姓名。
    2. 上面已经回答了。这种数据库结构效率更高。

    编辑:基于使用电子邮件地址与 uid,关于此答案还有 2 个问题。

    1. 如果用户决定删除他的帐户并在一段时间后决定返回并尝试再次登录怎么办?如果我们使用email address,则不会发生任何事情。如果我们使用uid,当用户第二次登录时,会生成另一个uid,这显然与第一次不同,而这正是你遇到麻烦的时刻,因为即使他是同一用户,他被视为新用户。

    2. 如果用户的电子邮件地址发生变化怎么办?恕我直言,只有您决定更改电子邮件才能更改电子邮件。就个人而言,我已经多年没有更改我的电子邮件地址,但我已经从数百个应用程序中删除了数百个帐户。即使您更改电子邮件地址,也没有太大问题。您登录您的应用程序,更改电子邮件地址,仅此而已。您还将拥有该应用程序中的所有历史记录。拥有一个唯一标识符 uid,以防您删除帐户并再次返回,您从零开始。

    【讨论】:

    • @mido2009 不要这样做!!!使用电子邮件地址作为密钥是一个大问题!如果用户的电子邮件地址发生变化怎么办?您必须删除该节点,重新编写它并更改对该节点的所有其他引用!您还必须处理删除特殊字符和一堆其他东西。此外,您严重依赖于比直接访问节点更慢并且需要更多资源的查询。如果可能,最好直接访问节点而不是查询它们。
    • 哦,请参阅 this answer 了解更多信息。
    • Mido2009,@Jay 是这里最好的回答者之一,但请查看我的更新答案。由您决定哪个选项最适合您,但根据 Firebase 团队的说法,我认为这是正确的。杰,如果我错了,请告诉我。我想解释的是,我的回答是我在许多项目中看到的关于 Firebase 的常见做法。
    • 你的答案肯定是好的。 OP 需要决定什么最适合他们的用例。我试图挽救一些悲伤,因为可能需要能够更改电子邮件。请参阅 Firebaser 的 herethis answer 的以下帖子。 Firebase 生成的密钥的另一个好处是它们是顺序和堆叠的,而电子邮件则不是。
    • 关于#2,我不同意。如果更新了电子邮件地址,这可能是一个大问题。请记住,我们在这里讨论的不是单个节点,而是整个应用程序中的数十个节点,因为 Firebase 数据通常是非规范化的,因此该电子邮件地址会有很多引用/重复。更改后,整个数据库中的每个节点都需要用新电子邮件读入、删除和写回:很多 附加代码。使用uid作为父节点,email作为子节点,所有的引用都指向uid,所以更改email没有影响。
    【解决方案2】:

    学生登录后,我如何才能找到他们的个人资料信息,因为 parent 是唯一的 ID。

    超级简单!最初创建用户帐户时,Firebase 会为用户分配一个“随机”且不变的用户 uid (uid)。该 uid 是向 Firebase 识别该特定用户的内容。这就是您应该在用户节点下存储信息的内容,如下所示:

    users
      uid_0
        name: "users name"
    

    然后,当他们将来进行身份验证时,firebase 会在身份验证过程中为您提供该 uid。然后,您可以通过该 uid 从用户节点简单地获取他们的用户信息。即读取节点 /users/uid_0

    一旦你得到学生的名字,你怎么能搜索所有的 学生在数据库中保存的条目?

    再次,超级简单。对于您在 Firebase 中创建的每个条目,请引用该 uid。例如,假设您要跟踪每个用户的报告

    reports
       uid_0
         -9i9sdjj3i0a09djads  //create with push() or childByAutoId() in swift
            reportName: "some report"
         -ua9sd9i9i3i0idsfi
            reportName: "another report" 
    

    然后要获取他们的所有报告,请阅读节点 /reports/uid_0

    相反,您可以存储报告,然后是指向用户的链接

    reports
      -9i9sdjj3i0a09djads
         reportName: "some report"
         report_by: "uid_0"
    

    使用该结构,可以在 report_by 等于“uid_0”的情况下进行查询,以返回所有 uid_0 的报告。

    不确定我设置数据库的方式是否理想,是否有更好的 怎么办?

    有许多不同的方法可以实现您想要的,但以上是一种非常常见的设计模式。

    【讨论】:

    • Jay 和 Alex,非常感谢你们!这很有帮助。
    • 我还有两个问题需要帮助:可以提交的报告数量有限,比如说 10 种不同的可能报告。 (1) 如何检查报告是否存在?我将不得不检查“location”、“mode”、“spinnerOne”的值,并将它们与用户刚刚输入的内容进行比较,如果它已经存在则不要添加到数据库中,如果是则添加它。我使用 for 循环浏览报告,但它不适合我。 (2) 我有一个列表视图中的报告,我想允许用户删除报告我应该怎么做?
    • @Mido2009 这确实是另一个问题,但是您可以将复合值(规格:location_mode_spinnerOne)与observeSingleEvent 结合起来,以查看该节点是否已经存在。对此进行一些研究,然后发布另一个包含一些细节的问题,我们会看看。
    • @Mido2009 决定你不喜欢我的回答?是否还有其他未回答的问题?
    猜你喜欢
    • 1970-01-01
    • 2017-08-14
    • 2018-02-26
    • 2023-03-09
    • 2013-12-14
    • 1970-01-01
    • 2020-12-12
    • 2017-09-07
    相关资源
    最近更新 更多