非关系型数据库设计 - MongoDB

5
我正在尝试构建一个应用程序,其中只有这三个模型:
- 主题(只有一个标题(最多100个字符)) - 评论(具有文本(可能非常长)、作者ID、主题ID、创建日期) - 作者(只有一个用户名)
实际上是一个非常简单的数据库结构。一个主题可以有多个评论,这些评论由作者创建。一个作者可以有多个评论。
我仍在努力找出设计数据库结构(文档)的最佳方法。一开始我想把所有东西都放在自己的架构中,就像上面那样。三个文档。但既然这是一个nosql数据库,我应该尽量消除对连接的需求。现在我真的在考虑把所有东西都放在一个文档中,听起来也很疯狂。
这些是我的实际查询:
- 首页查询:列出今天收到最多评论的所有主题(经常运行) - 搜索字段的自动建议列表:列出标题包含字符串“X”的所有主题 - 主题的主页面查询:列出一个主题的所有评论,以及它们的作者的用户名
由于我的大多数查询都需要来自至少两个文档的数据,所以我真的应该像这样将它们全部放在单个文档中吗?
评论(文本、用户名、主题标题、创建日期)
这样我将不需要任何连接,但也会多次保存主题的标题,例如在每个评论中。
我只是无法决定。

一个主题可能有很多评论,数量是多少?几十个,几百个? - prasad_
实际上是成千上万的.. - akcasoy
我的意思是每个主题有多少评论?每个主题都有数千条评论吗?如果是这样,我已经更新了我的答案。 - prasad_
大多数情况下是几百个,但每个主题可能会有成千上万。 - akcasoy
4个回答

1
您也可以采取稍微不同的方法。在某些情况下,存储冗余信息并不是一件坏事。

1. 首页查询:列出今天收到最多评论的所有主题(经常运行)

您可以在主题实体中实现此操作,添加两个额外字段。一个描述上次添加评论的日期,另一个计算当天添加的评论数量。这样做,您无需连接,可以编写仅查看主题集合的查询。

您还可以独立存储这些统计数据,并在需要时更新它。将其视为描述数据库当前状态的文档(至少与您相关的部分)。

这可能会导致存储信息的时间成本增加,但可以提高读取时间。

2. 搜索字段的自动建议列表:列出所有标题包含字符串“X”的主题

据我所知,您只需要主题标题。这意味着您可以查询数据库一次并检索所有标题。如果集合变得很大,这变得很慢,您可以触发检索查询的刷新,仅返回子集(用户不太可能浏览100个可能的主题)。

3. 话题查询的主页面:列出一个话题的所有评论,以及它们作者的用户名。

这其实是一个棘手的问题。如果这确实是你想要做的事情,那么最好将所有数据存储在一个文档中。然而,我想问你:为什么不能进行多个查询?当有数千条评论时,我怀疑你不会一次性显示所有评论。除了将每个评论存储在单独的文档中或将所有评论存储在一个文档中之外,您还可以对它们进行分组,并检索最近的20条评论(如果您创建的桶大小为20)。阅读更多关于桶模式的信息here,并根据需要更新显示的评论。


1
你可以采用你提出的第二种设计,但这取决于你如何使用数据。我假设你将在网站中使用它。
如果你想让评论可点击,例如点击主题名称将重定向到主题页面或点击用户名将重定向到用户页面,你可以将它们保留为ID。因为你以后可以使用 .populate("field1 field2") 并选择要从该ID获取的字段。
或者,你可以将主题名称和用户名及其ID存储在同一文档中,以减少查询次数,但你最终将存储更多的冗余数据。

1

修改后的设计:

这三个查询(在问题帖子中)可能会像这样(伪代码):

  • 从评论中选择所有主题,日期为今天,按主题分组并计算评论数,按计数排序(降序)
  • 选择评论中与搜索匹配的主题,并按主题分组。
  • 从评论中选择所有与topic_param匹配的内容,按评论日期排序(降序)。

因此,如您所愿(在问题帖子中),很可能会有一个主要集合comments

评论:

  date
  author
  text
  topic

用户和话题集合各有一个字段,是可选的,以保持唯一性。
请注意,按组查询将是聚合查询,例如,主查询将如下所示:
db.comments.aggregate( [
  { $match: { date: ISODate("2019-11-15") } },
  { $group: { _id: "$topic", count: { $sum: 1 } } },
  { $sort: { count: -1 } }
] )

这将为您提供所有主题名称,以今天计算并按最高计数的主题为先。

但正如我之前所写的,我的主页一直在运行这个查询:“列出今天收到最多评论的所有主题”.. 所以我需要一直连接这两个文档.. 这真的是正确的方法吗? - akcasoy
我已经更新了答案,加入了这个:评论(有一个对话题名称的引用)。查询可以像这样(伪代码):“从评论中选择所有主题,日期为今天,按主题分组并计算评论数量,按评论数量降序排序”。这将给出所有主题名称,今天和最高计数的主题排在前面。 - prasad_
我已经修改了答案。 - prasad_

0
你说:
“由于我的大多数查询需要来自至少两个文档的数据,所以我真的应该像这样将它们全部放在一个单独的文档中吗...”
我会从“领域驱动设计”的角度进行论述。假设所有数据都存在于同一有界上下文(业务领域)中。那么将其全部封装在同一文档中是可以接受的!

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