【问题标题】:Recommended Firebase data structure for my app为我的应用推荐的 Firebase 数据结构
【发布时间】:2017-10-10 06:04:45
【问题描述】:

问题是关于我为 Firebase 应用程序定义的数据结构。 它正在工作,但是我对效率和可扩展性表示怀疑。

想象一个只有一个全局聊天室的聊天应用程序 但您只会看到与您有关系的用户的消息。 从这个意义上说,“关系”意味着您共享相同的组成员身份。 这些是组:

+---------+---------+---------+
| Group A | Group B | Group C |
+---------+---------+---------+
| User1   | User4   | User7   |
| User2   | User5   | User8   |
| User3   | User6   | User1   |
+---------+---------+---------+

请注意,User1 是 A 组和 C 组的成员。 概念是 User1 将看到 User 2、3、7 和 8 发布的消息 而 User4 只会看到来自用户 5 和 6 的消息。 为此,每个用户的关系都存储在 Firebase 实时数据库中,如下所示:

Friends
├── User1
│   ├── User2: true
│   ├── User3: true
│   ├── User7: true
│   └── User8: true
├── User2
    ├── User1: true
    └── User3: true

等等。出于演示目的,我在这里使用用户名,实际上,这些是 Firebase UID。 显然,这需要将许多 (users_per_group)² 条目写入数据库。 每组可能的组数和用户数是无限的。 消息像这样添加到 Firebase:

Messages
├── User1
│   ├── timestamp
│   │   └── message: "This is a message"
│   ├── timestamp
│   │   └── message: "This is another message"
├── User2
    ├── timestamp
    │   └── message: "..."

通过以下 Firebase 安全规则可以轻松实现权限的实际执行:

"Messages": {
    "$uid": {
        // allow read only if the current user is a friend of the message creator
        // OR if the user is the creator of the message
        ".read": "(root.child('Friends/' + $uid + '/' + auth.uid).val() === true || $uid === auth.uid)"
    }
}

这是构建数据的推荐方法吗? 由于跟踪用户关系所需的数据量,我有点不确定。

【问题讨论】:

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


    【解决方案1】:

    当我们谈论效率和可扩展性时,Firebase 中最重要的规则是让数据尽可能扁平化。根据这条规则,我建议你像这样改造你的数据库:

    firebase-url
        |
        --- users
        |     |
        |     ---- userId_1
        |     |       |
        |     |       ---- userName: "John"
        |     |       |
        |     |       ---- userAge: 30
        |     |       |
        |     |       ---- groups
        |     |              |
        |     |              ---- groupName1 : true
        |     |              |
        |     |              ---- groupName2 : true
        |     |
        |     ---- userId_2
        |             |
        |             ---- userName: "Anna"
        |             |
        |             ---- userAge: 25
        |             |
        |             ---- groups
        |                    |
        |                    ---- groupName3 : true
        |                    |
        |                    ---- groupName4 : true
        |
        ---- groups
        |      |
        |      ---- groupIdId_1
        |            |
        |            ---- groupName: "groupName1"
        |            |
        |            ---- users
        |                   |
        |                   ---- userId_1: true
        |                   |
        |                   ---- userId_2: true
        |
        --- messages
              |
              ---- groupId_1
                      |
                      ---- messageId_1
                      |       |
                      |       ---- messageText: "Hello!"
                      |       |
                      |       ---- messageTimeStamp: 1492189663846
                      |
                      ---- messageId_2
                              |
                              ---- messageText: "Hy!"
                              |
                              ---- messageTimeStamp: 1492189685692
    

    通过这种方式,您可以非常简单地查询数据库以显示属于单个组的所有用户:firebase-url/groups/groupId/users/。用户所属的所有组:firebase-url/users/userId/groups/ 以及来自单个组的所有消息:firebase-url/groupId_1/

    要了解有关正确构建 Firebase 数据库的更多信息,请阅读post

    希望对你有帮助。

    【讨论】:

    • 感谢您的回复并同意这是典型聊天应用程序的首选结构。然而,在我的示例中,只有一个全局聊天室,没有必要在每个组的基础上跟踪消息。正如您确认最重要的方面是使数据尽可能平坦,我觉得我目前的结构走在正确的轨道上。我真正担心的是可扩展性方面,例如当有 1000 个用户的组和一个新用户加入时。
    • 如您所说,这是典型聊天应用程序的首选数据库结构。因此,在您的情况下,请勿使用 groups 部分。在可扩展性方面,使用这种结构,不会造成麻烦。我还建议您尝试真实案例场景。以编程方式生成 1000 个用户。成为第 1001 个用户,看看会发生什么。所以,祝你好运,让我知道! ;)
    • 一切都好吗?我可以帮助您了解其他信息吗?
    【解决方案2】:

    很抱歉让您失望了,但很遗憾您无法使用此数据结构来实现您想要实现的目标。

    首先,只要组中没有太多用户,数据树的性能就应该没问题。我通过重建您概述的数据结构并将一个玩家一个接一个地添加到组中来测试解决方案的性能,同时在 Firebase 实时数据库中创建他们之间的“朋友”关系。结果如下:

    Added user #10. Needed time: 0.00156599283218384 seconds
    Added user #30. Needed time: 0.00276100635528564 seconds
    Added user #50. Needed time: 0.00490301847457886 seconds
    Added user #100. Needed time: 0.013949990272522 seconds
    Added user #150. Needed time: 0.0460770130157471 seconds
    Added user #200. Needed time: 0.0947499871253967 seconds
    Added user #300. Needed time: 0.451290011405945 seconds
    Added user #400. Needed time: 1.81872600317001 seconds
    

    如您所见,小团体的表现似乎完全没问题。

    但问题主要不在于您希望如何存储数据,而更多地在于您希望如何获取数据。您写道,您希望使用数据库规则来获取允许用户查看的所有消息,具体取决于他的“朋友”关系。但这是某种过滤机制,在 Firebase 实时数据库中禁止/不可能借助数据库规则进行过滤。

    来自Firebase docs

    规则不是过滤器

    规则以原子方式应用。这意味着读或写 如果该位置没有规则,则操作立即失败 或在授予访问权限的父位置。即使每个受影响 子路径可访问,在父位置读取将失败 完全。

    还有……

    .read 和 .write 规则自上而下工作,规则较浅 覆盖更深层次的规则。

    这意味着您必须直接为您​​的 Messages 父节点定义某种读取规则。但是此规则随后会覆盖您对各个子节点的规则。

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-20
      • 2013-06-25
      • 2010-11-14
      • 2021-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多