我的应用推荐的Firebase数据结构

时间:2017-05-11 09:49:12

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

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

想象一下只有一个全球聊天室的聊天应用程序 但您只会看到与您有关系的用户发来的消息。 在这种意义上,“关系”意味着您共享相同的组成员资格。 这些是小组:

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

请注意,User1是A组和C组的成员。 概念是User1将看到用户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)"
    }
}

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

2 个答案:

答案 0 :(得分:2)

当我们谈论效率和可扩展性时,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/。用户为appart的所有组:firebase-url/users/userId/groups/以及来自单个组的所有邮件:firebase-url/groupId_1/

要详细了解如何正确构建Firebase数据库,请阅读此post

希望它有所帮助。

答案 1 :(得分:1)

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

首先,只要组中没有太多用户,数据树的性能就应该很好。我通过重建您概述的数据结构并在创建朋友" 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 父节点定义某种读取规则。但是,此规则将覆盖相应子节点的规则。

希望这有帮助!