2013-05-07 101 views
91

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

我有一个简单的例子:

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

回答

119

UPDATE:现在有doc on structuring data。另外,请参阅NoSQL data structures上的优秀帖子。

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

您也想在denormalize的地方读取效率的问题。这是所有大型应用程序(例如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)); 

这种方法的问题在于我刚刚强制客户端下载了所有用户的messageswidgets。如果这些东西中没有一个数字是成千上万,那么没有什么可比的但对于10k用户而言,每个消息都有5k以上的信息是很重要的。

所以,现在的层次,实时结构的最优策略变得更加明显:

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

一个额外的工具,它是在这种环境下非常有用的指标。

/users_with_gmail_accounts/uid/email 

现在,如果我想,说,获得Gmail用户的邮件,我可以做这样的事情:通过创建具有特定属性的用户的一个指标,我可以快速简单地迭代指数模拟的SQL查询:

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张贴关于非规范化的数据,so check those out as well。我看到弗兰克已经发布了阿南特的文章,所以我不会在这里重申,但这也是一个很棒的阅读。

+0

感谢您的洞察加藤! – 2013-05-07 19:54:38

+4

我是否必须手动管理这些索引? – fiatjaf 2013-11-26 02:34:54

+2

暂时。 Firebase v2版本中的视图将包含一些用于自动执行该过程的强大功能。 – Kato 2013-11-26 16:46:45

44

Firebase非常多而不是像关系数据库那样的。如果你想将它与任何东西进行比较,我会将它与分层数据库进行比较。

阿南特最近写了一个伟大的职位上的火力地堡博客关于非规范化的数据:https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html

我的确会建议保持每个应用程序的“ID”为每个申请人的孩子。

+0

Yuppers!好帖子!谢谢你提醒我。 – Kato 2013-05-07 15:54:26

+0

谢谢弗兰克!这真的很有帮助。正是我在找什么! – 2013-05-07 19:54:20

3

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

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

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

好,但我有一个后续的,我们如何从Swift或使用Firebase SDK的任何地方创建此结构?另外我们如何验证添加到应用程序节点的新数据实际上是否存在使用Firebase验证规则的应用程序列表中? – 2016-11-20 20:21:03

+0

@prateep,很好的例子。但是,这里的问题是,当我删除路径应用程序/ application1其中application1是一些申请人的孩子。如果我尝试访问不在那里的路径申请人/ application1。因此您需要在application1:{applicants:{applicant1:true} ...}这两个地方更新索引,所以现在当我删除applicantion1时,我必须检查它是否是子应用程序并更新应用程序的子节点。 :) – 2016-12-18 11:37:48

相关问题