在firebase上构建数据的最佳方法是什么?

时间:2013-05-07 14:10:01

标签: firebase data-structures nosql firebase-realtime-database

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

我有一个简单的例子:

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

3 个答案:

答案 0 :(得分:134)

更新:现在有一个doc on structuring data。另外,请参阅NoSQL data structures上的这篇优秀文章。

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

您还希望denormalize在需要考虑阅读效率的地方。这是所有大型应用程序(例如Twitter和Facebook)使用的技术,虽然它违反了我们的DRY原则,但它通常是可扩展应用程序的必要功能。

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

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

这种方法的问题在于我刚刚强迫客户端下载所有用户messageswidgets。如果这些东西中没有一个成千上万,那就没什么大不了的。但对于拥有超过5k消息的10k用户来说,这是一笔大买卖。

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

/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 check those out as well。我看到弗兰克已经发布了Anant的文章,所以我不会在这里重申,但这也是一个很好的阅读。

答案 1 :(得分:48)

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

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

我的确建议将每份申请的“身份证”保留为每位申请人的子女。

答案 2 :(得分:4)

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

    memcache_results = memcache.get(root_url, namespace='charlotte')
    if memcache_results:
        if url in memcache_results:
            return False
        else:
            pass
    else:
        memcache_results = []
    memcache.add(root_url, memcache_results.append(url), 60 * 60, namespace='charlotte')

    print memcache_results

    charlotte = SpiderWorker(root_url)
    charlotte.get_page(url)
    links = charlotte.grab_links()

    for url in links:
            deferred.defer(spin_worker, root_url=root_url, url=url, _queue='doc-repo')