119

我是 firebase 新手,我想知道在其上构建数据的最佳方式是什么。

我有一个简单的例子:

我的项目有申请人和申请。1个申请人可以有多个申请。如何在 firebase 上关联这 2 个对象?它像关系数据库一样工作吗?还是在数据设计方面需要完全不同的方法?

4

3 回答 3

150

更新:现在有一个关于结构化数据的文档另外,请参阅这篇关于NoSQL 数据结构的优秀文章。

与 RDBMS 相比,分层数据的主要问题是嵌套数据很诱人,因为我们可以。通常,尽管缺少连接语句和查询,您仍希望在某种程度上规范化数据(就像使用 SQL 一样)。

您还希望在关注读取效率的地方进行非规范化。这是所有大型应用程序(例如 Twitter 和 Facebook)都使用的技术,尽管它违反了我们的 DRY 原则,但它通常是可扩展应用程序的必要功能。

这里的要点是,您要努力进行写入以使读取变得容易。将单独阅读的逻辑组件分开(例如,对于聊天室,不要将消息、关于房间的元信息和成员列表放在同一个地方,如果您希望以后能够迭代组)。

Firebase 的实时数据和 SQL 环境之间的主要区别在于查询数据。没有简单的方法可以说“SELECT USERS WHERE X = Y”,因为数据的实时性(它不断变化、分片、协调等,这需要更简单的内部模型来控制同步客户端)

一个简单的例子可能会让你处于正确的心态,所以这里是:

/users/uid
/users/uid/email
/users/uid/messages
/users/uid/widgets

现在,由于我们处于分层结构中,如果我想迭代用户的电子邮件地址,我会这样做:

// I could also use on('child_added') here to great success
// but this is simpler for an example
firebaseRef.child('users').once('value')
.then(userPathSnapshot => {
   userPathSnapshot.forEach(
      userSnap => console.log('email', userSnap.val().email)
   );
})
.catch(e => console.error(e));

这种方法的问题是我刚刚强迫客户端也下载所有messages用户widgets。如果这些东西都没有以数千计,那也没什么大不了的。但对于 10k 个用户来说,每个用户都有超过 5k 条消息,这很重要。

因此,现在分层实时结构的最佳策略变得更加明显:

/user_meta/uid/email
/messages/uid/...
/widgets/uid/...

在这种环境中非常有用的另一个工具是索引。通过创建具有某些属性的用户索引,我可以通过简单地迭代索引来快速模拟 SQL 查询:

/users_with_gmail_accounts/uid/email

现在,如果我想为 gmail 用户获取消息,我可以这样做:

var ref = firebase.database().ref('users_with_gmail_accounts');
ref.once('value').then(idx_snap => {
   idx_snap.forEach(idx_entry => {
       let msg = idx_entry.name() + ' has a new message!';
       firebase.database().ref('messages').child(idx_entry.name())
          .on(
             'child_added', 
             ss => console.log(msg, ss.key);
          );
   });
})
.catch(e => console.error(e));

我在另一篇关于非规范化数据的 SO 帖子中提供了一些详细信息,所以也请检查一下。我看到弗兰克已经发布了 Anant 的文章,所以我不会在这里重复,但这也是一个很好的阅读。

于 2013-05-07T15:47:24.767 回答
50

Firebase与关系数据库非常不同。如果您想将其与任何东西进行比较,我会将其与分层数据库进行比较。

Anant 最近在 Firebase 博客上写了一篇关于非规范化数据的精彩文章:https ://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html

我确实建议将每个申请的“ID”保留为每个申请人的孩子。

于 2013-05-07T15:34:55.550 回答
4

您的场景在关系世界中看起来像一对多,根据您的示例,申请人有许多应用程序。如果我们采用 firebase nosql 方式,它如下所示。它应该在没有任何性能问题的情况下扩展。这就是为什么我们需要如下所述的非规范化。

applicants:{
applicant1:{
    .
    .
    applications:{
        application1:true,
        application3:true
    }
},
applicant2:{
    .
    .
    applications:{
        application2:true,
        application4:true
    }
}}

applications:{
application1:{
    .
    .
},
application2:{
    .
    .
},
application3:{
    .
    .
},
application4:{
    .
    .
}}
于 2016-02-23T19:46:42.680 回答