Mongodb:将所有相关数据存储在一个集合中或相互抽象数据?

时间:2016-12-31 12:20:22

标签: mongodb

架构:

articles: [
  {
    _id: uid,
    owner: userId,
    title: string,
    text: text,
  }
],
comments_1: [
  {
    // single comment
    articleId: uid,
    text: text,
    user: {
      name: string,
      id: uid
    }
  }
],
comments_2: [
  {
    // all comments at once
    articleId: uid,
    comments: [
      {
        _id: commentId,
        text: text,
        user: {
          name: string,
          id: uid
        }
      }
    ],
  }
],

我对mongodb建议有点困惑: 说,我需要检索文章页面的信息。我需要做2个请求,首先找到id的文章,第二个找到评论。如果我在每篇文章中都包含评论(comments_2)作为属性,我只需要执行一个查询来获取我需要的所有数据,如果我需要列出的话,那么20篇文章的标题,我将使用要检索的指定属性执行查询,对吧?

  1. 我应该将评论和文章存储在不同的馆藏中吗?
  2. 如果评论将在不同的商店中,我应该以{{1​​}}方式还是comments_1方式存储评论?
  3. 我会避免深刻的解释,因为模式清楚地解释了我的观点,我想。简而言之,如果最好将所有内容存储在一个位置,然后在查询时指定要检索的属性,或者将数据抽象到不同的集合中,那么我不知道吗?

3 个答案:

答案 0 :(得分:1)

在关系数据库中,这将由JOIN实现。显然,there is a NoSQL equivalent in MongoDB,从版本3.2开始,名为 $ lookup

这允许您将注释和文章保存在单独的模式中,但仍然可以使用单个查询检索文章的注释列表。

Stack Overflow Source

答案 1 :(得分:1)

这是您必须做出的典型权衡。这两种方法各有利弊,您必须选择最适合您用例的方法。几点投入:

单桌:

  • 快速加载单篇文章,因为您在一个查询中加载所有数据
  • 加载20篇文章的标题没有问题(您只能使用projection
  • 查询字段的子集

多桌:

  • 更容易进行垂直查询(例如特定用户发表的评论等)
  • 我会使用版本1,因为它更简单,版本2不会给你带来任何好处

答案 2 :(得分:1)

嗯,MongoDB模型通常用于保存数据和关系,因为它不提供JOINS($ lookup是最接近加入且成本高,最好避免)。

这就是为什么在DB建模中非常强调非规范化,因为存储在一起有两个好处

  1. 您不必加入集合,只需一次查询即可获取数据。
  2. 由于mongo提供原子更新,您可以一次更新注释和文章,而不必担心事务和回滚。
  3. 所以几乎可以肯定你想在文章集中添加评论。所以它会像

    articles: [
      {
        _id: uid,
        owner: userId,
        title: string,
        text: text,
        comments: [
          {
            _id: commentId,
            text: text,
            user: {
              name: string,
              id: uid
            }
          }
        ]
      }
    ]
    

    在我们同意之前,让我们看看上述方法的缺点。

    1. 每个文档的限制为16MB,但是如果您的文章文本很大并且该文章的评论也很多,则可能会超过16 MB。

    2. 出于其他目的而获得文章的所有地方,您可能必须排除评论字段,否则会很重且很慢。

    3. 如果您必须再次进行聚合,如果我们需要根据评论以某种方式聚合,我们可能会遇到内存限制问题。

    4. 这些是严重的问题,我们不能忽视这一点,现在我们可能希望将它保存在不同的集合中,看看我们正在失去什么。

      首先评论和文章虽然是链接的但是是不同的实体,所以你可能永远不需要为任何领域一起更新它们。

      其次,您必须单独加载注释,这在正常用例中是有意义的,在大多数应用程序中,这是我们如何进行,所以这也不是问题。

      因此,在我看来,明显的获胜者有两个单独的收藏

      articles: [
        {
          _id: uid,
          owner: userId,
          title: string,
          text: text,
        }
      ],
      comments: [
        {
          // single comment
          articleId: uid,
          text: text,
          user: {
            name: string,
            id: uid
          }
        }
      ]
      

      如果你选择两种收集方法,你不会想要评论_2的方式,再次出于同样的原因,如果对一篇文章有​​大量评论的话。