我正在调查针对Android的Firebase数据库sample 并意识到它以下列方式存储其数据:
我对NoSQL技术并不熟悉,并试图理解为什么我们必须在post
和posts
相应地保留每个user_posts
实体两次。文档说这种方法被称为“扇出”,我完全同意通过像databaseReference.child("user-posts").child("<user_uid>")
之类的简单构造访问用户的帖子可能很有用。但是为什么我们需要posts
节点呢?如果我们需要更新一些帖子怎么办?我们必须做两次吗?
// [START write_fan_out]
private void writeNewPost(String userId, String username, String title, String body) {
// Create new post at /user-posts/$userid/$postid and at
// /posts/$postid simultaneously
String key = mDatabase.child("posts").push().getKey();
Post post = new Post(userId, username, title, body);
Map<String, Object> postValues = post.toMap();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/posts/" + key, postValues);
childUpdates.put("/user-posts/" + userId + "/" + key, postValues);
mDatabase.updateChildren(childUpdates);
}
// [END write_fan_out]
所以我想知道......当这种方法有用时,何时不是? Firebase SDK是否提供了在更新或删除数据时保持所有重复项同步的任何工具?
更新:以下是Firebase小组的解释received:
帖子重复的原因是因为我们希望能够 快速获取属于用户的所有帖子(如您所建议的)和 从所有帖子的列表中过滤以获得一个用户的帖子 随着帖子数量的增加,可能会变得非常昂贵。
这确实意味着我们必须在两个位置更新帖子 每当我们更新它。它使代码有点丑陋但是从那以后 查询比写入更常见,优化更好 阅读数据。
我怀疑这种方法可能看起来不太优雅,但它可能是大型数据集的最快选择,只要你比UPDATE更频繁地执行SELECT。但是,在某些情况下,我宁愿坚持使用此处推荐的其他解决方案。
答案 0 :(得分:7)
Data Fan Out是管理大量数据的绝佳技术。如果不使用此模式,将来可能会出现严重的扩展问题。
我从您的数据库结构中看到的是,您要存储整个帖子信息两次,这不是一个好习惯。您希望在另一个节点下存储仅对帖子的引用。因此,您将拥有一个名为users-posts
的节点,该节点将包含用户密钥,并且每个密钥都将包含一组值为true
的帖子密钥。为了更清楚:
这样,您就可以跟踪用户在users-posts
节点下编写的帖子;以及在posts
节点下编写每个帖子的用户。现在,您可能需要获取所有用户帖子的列表。您需要做的是在users-posts/USER_KEY/
节点上将获取密钥与用户编写的所有帖子同步,然后使用帖子获取更多帖子信息你得到的关键。
为什么建议使用此数据库设计?因为您为每次同步获取的信息少得多(使用Firebase,我们不会发出请求本身,因此我将读取称为同步)。在您的示例中,如果您将一个监听器附加到user-posts/USER_KEY/
以获取所有帖子的列表,您还会要求所有 每个和每个的信息他们写的帖子。使用数据扇出方法,您可以直接询问发布所需信息,因为您已经拥有帖子的密钥。
答案 1 :(得分:2)
在我看来,这不是一个好方法,因为您需要保持这些数据的同步,而Firebase不提供任何工具来保持重复同步。一种好方法是仅在user-posts
中存储密钥。
我建议阅读本文,了解如何构建数据非常有趣:https://www.firebase.com/docs/web/guide/structuring-data.html