【问题标题】:Nosql database design - MongoDBNosql 数据库设计 - MongoDB
【发布时间】:2020-03-06 14:53:53
【问题描述】:

我正在尝试构建一个只有这 3 个模型的应用:

  • 主题(只有一个标题(最多 100 个字符。))
  • 评论(有文本(可能很长)、author_idtopic_idcreatedDate)李>
  • 作者(只有一个用户名

其实是一个非常简单的db结构。一个主题可能有许多由作者创建的 cmets。并且一个作者可能有很多 cmets。

我仍在尝试找出设计数据库结构(文档)的最佳方式。首先,我想把所有东西都放在它自己的模式中,就像上面一样。 3 文件。但由于这是一个 nosql 数据库,我实际上应该尝试消除对连接的需求。现在我真的在考虑将所有内容都放在一个文档中,这听起来也很疯狂。

这些是我从 ui 实际查询的:

  • 首页查询:列出今天收到最多 cmets 的所有主题(会经常运行)
  • 搜索字段的自动建议列表:列出所有标题包含字符串“X”的主题
  • 主题查询的主页:列出一个主题的所有 cmets,并附上作者的用户名。

由于我的大多数查询都需要来自至少 2 个文档的数据,我真的应该像这样在一个文档中一起使用它们吗:

评论(文本用户名topic_titlecreatedDate

这样我就不需要任何加入,但也可以多次保存主题的标题..在每条评论中..

我只是无法决定。

感谢您的帮助。

【问题讨论】:

  • “一个主题可能有很多个cmets”,有多少个?几十个,几百个?
  • 实际上超过了 ..
  • 我的意思是每个主题有多少 cmets?每个主题数千?如果是这样,我已经更新了我的答案。
  • 大部分时间都是数百个。但每个主题可能有数千个。

标签: mongodb database-design nosql


【解决方案1】:

您可以进行您建议的第二种设计,但这一切都取决于您希望如何使用数据。我假设您会将其用于网站。

如果您希望 cmets 可点击,这样点击主题名称将重定向到主题页面或点击用户名将重定向到用户页面,您可以在其中看到他的所有 cmets,我建议您将它们保留为身份证。因为您以后可以使用.populate(“field1 field2”),并且可以选择您想从该 ID 中获取的字段。

或者,您可以将 topic_name 和 username 及其 ID 存储在同一个文档中以减少查询,但最终会存储更多冗余数据。

【讨论】:

    【解决方案2】:

    修改后的设计:

    三个查询(在问题帖中)很可能是这样的(伪代码):

    • 从 cmets 中选择所有主题,其中日期为今天,按主题分组并计数 cmets,按计数排序 (desc)
    • 从 cmets 中选择主题,其中主题匹配搜索,按主题分组。
    • 从 cmets 中选择所有,其中 topic 匹配 topic_param,按 comment_date (desc) 排序。

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

    cmets:

      date
      author
      text
      topic
    

    用户和主题集合各有一个字段,是可选的,以保持唯一性。

    注意分组查询将是聚合查询,例如,主查询将是这样的:

    db.comments.aggregate( [
      { $match: { date: ISODate("2019-11-15") } },
      { $group: { _id: "$topic", count: { $sum: 1 } } },
      { $sort: { count: -1 } }
    ] )
    

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

    【讨论】:

    • 但是正如我在上面写的那样,我的主页一直在运行这个查询“列出今天收到最多 cmets 的所有主题”.. 所以我再次需要将这两个文档都加入时间..这真的是要走的路吗?
    • 我已经用这个更新了答案:cmets(引用了 topic_name)。查询可以是这样的(伪代码):“从 cmets 中选择所有主题,其中日期是今天,按主题分组并计数 cmets,按 desc by count 排序”。这将为您提供今天的所有主题名称,并首先提供计数最高的主题。
    • 我已经修改了答案。
    【解决方案3】:

    您也可以采取一些不同的方法。在所有情况下,冗余存储信息都不是坏事。

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

    您可以将其作为主题实体中的两个额外字段来实现。一个描述添加评论的最后日期,第二个描述当天添加的 cmets 数量。通过这样做,您无需加入,但可以编写只查看主题集合的查询。

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

    这可能会给您存储信息带来时间上的损失,但会缩短阅读时间。

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

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

    3.主题查询的主页:列出一个主题的所有 cmets,及其作者的用户名。

    这实际上是一个棘手的问题。如果这确实是您想要做的,那么您很可能最好将所有数据存储在一个文档中。但是我会问你:进行多个查询的问题是什么?我怀疑当有数千个(如您所说)时,您会立即显示所有 cmets。除了将每个存储在单独的文档中或将所有内容都放入一个文档中,您还可以对它们进行存储并仅检索 20 个最近的存储(如果您要创建大小为 20 的存储桶)。阅读更多关于存储桶模式here 的信息,并在需要时更新显示的内容。

    【讨论】:

      【解决方案4】:

      你说:

      “由于我的大多数查询都需要来自至少 2 个文档的数据,我真的应该像这样在一个文档中一起使用它们吗……”

      我将从“领域驱动设计”的角度进行论证。 假设您的所有数据都存在于同一个有界上下文(业务领域)中。那么就可以将其全部封装在同一个文档中了!

      【讨论】:

        猜你喜欢
        • 2012-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-14
        • 2017-10-23
        • 1970-01-01
        相关资源
        最近更新 更多