什么';在firebase上构建数据的最佳方式是什么?

什么';在firebase上构建数据的最佳方式是什么?,firebase,data-structures,nosql,firebase-realtime-database,Firebase,Data Structures,Nosql,Firebase Realtime Database,我是firebase的新手,我想知道在firebase上构建数据的最佳方式是什么 我有一个简单的例子: 我的项目有申请者和申请者。1申请人可以有多份申请。如何在firebase上关联这两个对象?它是否像关系数据库一样工作?或者这种方法在数据设计方面需要完全不同 Firebase与关系数据库非常不同。如果您想将它与任何东西进行比较,我会将它与分层数据库进行比较 Anant最近在Firebase博客上写了一篇关于数据非规范化的文章: 我确实建议将每个申请的“ID”保留为每个申请人的子女。更新:现在有

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

我有一个简单的例子:

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

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

Anant最近在Firebase博客上写了一篇关于数据非规范化的文章:


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

更新:现在有一个。另外,请参阅上的这篇精彩文章

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

您还希望在需要考虑阅读效率的地方使用。这是所有大型应用程序(如Twitter和Facebook)都使用的一种技术,尽管它违背了我们的枯燥原则,但它通常是可伸缩应用程序的必要功能

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

Firebase的实时数据与SQL环境的主要区别在于查询数据。由于数据的实时性,没有简单的方法说“选择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));
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));
这种方法的问题是,我刚刚强制客户端下载所有用户的
消息
小部件
。如果这些东西都不是成千上万的话,那就没什么大不了的了。但对于拥有超过5万条信息的10万用户来说,这是一件大事

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

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

/users_with_gmail_accounts/uid/email
现在,如果我想,比如说,为gmail用户获取消息,我可以这样做:

// 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));
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));

我在另一篇关于数据非规范化的文章中提供了一些细节。我看到Frank已经发布了Anant的文章,所以我在这里不再重复,但这也是一个很好的阅读。

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

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

applications:{
application1:{
    .
    .
},
application2:{
    .
    .
},
application3:{
    .
    .
},
application4:{
    .
    .
}}

谢谢你,弗兰克!这真的很有帮助。正是我要找的!谢谢你的洞察力加藤!暂时。Firebase v2版本中的视图将包含一些伟大的功能,用于自动化该过程。注意到我在这里重新启动了一个旧的评论线程,但我正在努力找到一个更为最新的解决方案。这仍然是最好的方法吗?ie使用gmail帐户获取所有用户,然后运行forEach?很好,但我有一个后续问题,我们如何使用Firebase SDK从Swift或任何地方创建此结构?另外,我们如何使用Firebase验证规则验证添加到应用程序节点的新数据是否确实存在于应用程序列表中?@pratep,这是一个很好的例子。但这里的问题是当我删除路径applications/application1时,其中application1对于某些申请人来说是子级。如果我尝试访问不存在的路径“申请者/应用程序1”。因此,您需要在两个位置更新索引,如application1:{applications:{application1:true}…},因此,现在当我删除application1时,我必须检查它的子申请者并更新申请者的子节点。:)