假设我有一个典型的用户和分组数据模型,其中用户可以在许多组中,并且组可以有许多用户。在我看来,firebase docs建议我通过在用户内部复制用户ID以及用户内部的组ID来建模我的数据:
{
"usergroups": {
"bob": {
"groups": {
"one": true,
"two": true
}
},
"fred": {
"groups": {
"one": true
}
}
},
"groupusers": {
"one": {
"users": {
"bob": true,
"fred": true
}
},
"two": {
"users": {
"bob": true
}
}
}
}
为了维护这种结构,每当我的应用程序更新关系的一方(例如,将用户添加到组)时,它还需要更新关系的另一方(例如,将组添加到用户) )。
我担心最终有人的计算机会在更新过程中崩溃,否则会出现其他问题,并且关系的双方将会失去同步。理想情况下,我想将更新放在一个事务中,以便双方都得到更新或双方都没有,但据我所知,我不能用firebase中的当前事务支持来做到这一点。
另一种方法是使用即将推出的firebase触发器来更新关系的另一面,但触发器尚未可用,并且它似乎是一个非常重量级的解决方案,只是为了让服务器保持该服务器保持向外部服务器发布消息冗余数据最新。
所以我正在考虑另一种方法,其中许多用户组成员资格被存储为一个单独的端点:
{
"memberships": {
"id1": {
"user": "bob",
"group": "one"
},
"id2": {
"user": "bob",
"group": "two"
},
"id3": {
"user": "fred",
"group": "one"
}
}
}
我可以在“user”和“group”上添加索引,并发出firebase查询“.orderByChild(”user“)。equalTo(...)”和“。orderByChild(”group“)。equalTo(.. 。)“分别确定特定用户的组和特定组的用户。
这种方法的缺点是什么?我们不再需要维护冗余数据,为什么这不是推荐的方法?它是否明显慢于推荐的复制数据方法?
答案 0 :(得分:5)
在您提出的设计中,您总是需要访问三个位置来向用户及其群组展示:
users
子项以确定用户的属性memberships
以确定她是groups
子项以确定组的属性在文档中的非规范化示例中,您的代码只需访问#1和#3,因为成员身份信息已嵌入users
和groups
。
如果再进一步规范化,则最终会存储每个用户的所有相关组信息以及每个组的所有相关用户信息。使用这样的数据结构,您只需要读取一个位置即可显示组或用户的所有信息。
冗余在NoSQL数据库中不一定是坏事,确实正是因为它加快了速度。
目前我会使用辅助流程定期扫描数据并协调它找到的任何不规则数据。当然,这也意味着常规客户端代码需要足够强大以处理此类不规则数据(例如,指向用户的组,其中该用户的记录不指向该组)。
或者,您可以设置一些高级.validate
规则,以确保双方始终保持同步。我总是发现需要更多时间来实现,所以从不打扰。
您可能还想阅读此答案:Firebase data structure and url