Firebase Firestore 评论树结构设计

16

我正在尝试在项目中实现一个Reddit/HackerNews风格的评论树,并尝试使用Firestore作为数据库解决方案。然而,通过阅读文档,我对正确的设计并不确定。在SQL数据库中,我会使用数字键,例如:

0
1.0
1.1
1.1.1
0.0

要表示我的树形结构。但是像那样的数字键似乎是Firebase反模式。另一种方式是在JSON中使用实际树来表示文章,例如:

{
  uid: 'A0000',
  content: 'foo',
  children: [
    {uid:..., content:..., children: []}]
}

据说在Firestore中,深度树是不好的。我理解深度树之所以不好是因为您必须获取整个树,但在我的情况下,我不确定这是否是个问题。一个客户端获取帖子将获取根内容节点和前20个或更多的子树。这可能会导致一次相当大的数据获取,但并不是非常疯狂。

有人知道实现这种结构的好方法吗?

额外信息:此结构在客户端处理后应如何呈现。

{
  uid: 0,
  title: 'Check out this cat!',
  body: 'It\'s pretty cute! This **text** is [markdown](link), so it can have ' +
    'links and *stuff*. Yay!',
  poster: {
    uid: 0,
    name: 'VivaLaPanda',
    aviUrl: 'badlink',
  },
  posted: '2018-03-28',
  children: [{
      uid: 0,
      body: 'This is a comment, it\'s angry!',
      poster: {
        uid: 0,
        name: 'VivaLaPanda',
        aviUrl: 'badlink',
      },
      posted: '2018-03-20',
      children: [{
        uid: 0,
        body: 'This is a comment, it\'s neutral!',
        poster: {
          uid: 0,
          name: 'Steve',
          aviUrl: 'badlink',
        },
        posted: '2018-03-20',
        children: [{
          uid: 0,
          body: 'This is a comment, it\'s neutral!',
          poster: {
            uid: 0,
            name: 'Craig',
            aviUrl: 'badlink',
          },
          posted: '2018-04-10',
          children: []
        }, ]
      }, ]
    },
    {
      uid: 0,
      body: 'This is a comment, it\'s happy!',
      poster: {
        uid: 0,
        name: 'Craig',
        aviUrl: 'badlink',
      },
      posted: '2018-03-28',
      children: []
    },
  ]
};

编辑:

虽然我已经将这个问题标记为已回答,因为确实有一个答案,但我仍然非常希望看到更加优雅/高效的解决方案。

编辑2:

供后人参考:最终我决定使用DGraph来处理数据,并且在身份验证方面使用Firebase。任何Firebase解决方案都过于复杂了。

2个回答

8

如果有很多人相互评论,那么您的孩子处理方式可能会变得非常混乱。更好的方法是为每个评论采用以下结构:

// single comment

postUid // <- random generated by firebase
{
    postedBy: userUid
    postedTime: timestamp
    postIsChildOfUid: postUid // <- reference to an other post (optional if the comment didn't respond to another comment(top-level comment))
}

这甚至不需要任何嵌套 :). 您现在可以轻松生成评论树,但这必须是客户端。但那应该很容易!

8

这很困难,因为你的结构自然上是递归的。显而易见的选择是将每个评论作为集合中的新文档,并且每个回复都是同一集合中的单个文档。

将每个评论作为一个新文档可能会像这样运作。每个评论都有一个“postId”属性,指定它属于哪个帖子。一些评论,那些是回复其他评论的,有一个“replyToId”。这两个属性结合起来允许您的客户端应用程序执行以下操作:

  1. 获取顶级评论(查找具有正确 postId 且没有 replyToId 的评论)。顶级评论允许您在将来需要担心载荷大小时限制负载大小。
  2. 获取所有评论(仅查找具有正确 postId 的评论)。如果您不关心载荷大小,可以获取所有内容并在客户端上处理树形结构。
  3. 获取特定评论的回复,如果您想要“查看回复”类似于 YouTube 的评论互动(查找具有特定 replyToId 的评论)。这与 1. 结合使用可有效地限制负载大小。

但是,这里的逻辑显然是复杂的。


那么在这个模型中,客户端会先获取根节点,然后是第一个子节点,接着是第二个子节点,以此类推? - VivaLaPanda
是的,或者获取所有评论。我认为你的Reddit风格的评论最好通过使用MemCache或类似工具的Web API来实现。然后,您只需要在Web API上获取所有评论并将它们缓存到MemCache中,并且仅向客户端提供部分结果集以节省带宽。 - Tom Bailey
@AdrianSmith 如果你有所成果,我很感兴趣看一下,请尽可能在这里分享。 - Tom Bailey
在使用父引用和子集合方面,有什么优势吗?从文档中我所看到的,它们在功能上是等效的。 - VivaLaPanda
1
@AdrianSmith 我认为使用父引用可能是更好的解决方案,因为当您使用Firestore API/客户端时,您不必担心孤立的子集合(删除父文档时不需要子集合)。 - Tom Bailey
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接