【问题标题】:MongoDB nested setsMongoDB 嵌套集
【发布时间】:2015-04-22 08:41:31
【问题描述】:

在 MongoDB 中存储嵌套集(如 cmets 树)的最佳实践是什么?

我的意思是,每条评论都可以有一个父评论和一个children-cmets(答案)。

像这样存储它们:

{
   title: "Hello",
   body: "Please comment me!",
   comments: [
        {
            author: "Peter",
            text: "Hi there",
            answers: [
                  {
                      author: "Peter",
                      text: "Hi there",
                      answers: [
                                 { author: "Ivan", text: "Hi there" },
                                 { author: "Nicholas", text: "Hi there" }
                      ]
                  },
                  { author: "Ivan", text: "Hi there" },
                  { author: "Nicholas", text: "Hi there" },
            ]
        },
        { author: "Ivan", text: "Hi there" },
        { author: "Nicholas", text: "Hi there" },
   ]
}

并不酷,因为我们不能,例如,在没有 map/reduce 的情况下要求“所有由 Peter 评论的帖子”。

【问题讨论】:

    标签: mongodb


    【解决方案1】:

    我认为没有完美的解决方案 - 取决于哪些操作对您的应用更重要。例如,我相信 Silicon Alley Insider 存储与 MongoDB 嵌套的 cmets。这确实使您提到的查询更难。

    一个选项是在帖子的顶层存储一个数组中所有评论者的列表。将其视为非规范化数据。然后可以很容易地找到所有涉及某个评论者的帖子。然后向下钻取,您可以使用 map/reduce 或 db.eval() 来获取其中的嵌套帖子信息。

    另一个注意事项 - 如果您正在处理单个文档,则 db.eval() 可能比 map/reduce 更轻量级。 $where 也是一个选项,但可能会很慢,所以我喜欢上面提到的附加“评论者列表” - 索引该数组也很容易(参见文档中的“多键”)。

    另请参阅: http://groups.google.com/group/mongodb-user/browse_thread/thread/df8250573c91f75a/e880d9c57e343b52?lnk=gst&q=trees#e880d9c57e343b52

    【讨论】:

      【解决方案2】:

      在 dm 的帖子 Dwight Merriman 的链接中提到使用路径键并进行正则表达式匹配

      {
        path : "a.b.c.d.e.f"
      }
      

      另一种方法是使用数组

      {
        path : ["a", "b", "c", "d", "e", "f"]
      }
      
      db.test.ensureIndex({path: 1})
      

      这应该会很快。

      如果每个节点只能在一个路径中,那么您无需担心它在列表中的位置

      db.test.find({path: "a"})
      

      会找到“a”的所有孩子

      我可能会使用节点的 _id 而不是路径名。

      更新

      • 需要注意的一点是,索引中只能包含一个数组。
      • 在查询中小心使用解释

        db.test.find({path: {$in: ["a", "b"]})

      给你

       db.test.find({path: {$in: ["a", "b"]}}).explain()
      {
              "cursor" : "BtreeCursor path_1 multi",
              "nscanned" : 2,
              "nscannedObjects" : 2,
              "n" : 1,
              "millis" : 0,
              "nYields" : 0,
              "nChunkSkips" : 0,
              "isMultiKey" : true,
              "indexOnly" : false,
              "indexBounds" : {
                      "path" : [
                              [
                                      "a",
                                      "a"
                              ],
                              [
                                      "b",
                                      "b"
                              ]
                      ]
              }
      }
      

      但是

       db.test.find({path: {$all: ["a", "b"]}}).explain()
      {
              "cursor" : "BtreeCursor path_1",
              "nscanned" : 1,
              "nscannedObjects" : 1,
              "n" : 1,
              "millis" : 0,
              "nYields" : 0,
              "nChunkSkips" : 0,
              "isMultiKey" : true,
              "indexOnly" : false,
              "indexBounds" : {
                      "path" : [
                              [
                                      "a",
                                      "a"
                              ]
                      ]
              }
      }
      

      仅使用第一个元素,然后扫描所有匹配结果以查找 b。
      如果 a 是您的根元素或在您的大部分记录中,那么您对记录进行了几乎完整的扫描,而不是有效的索引查询。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-14
        • 1970-01-01
        • 2021-12-05
        • 1970-01-01
        • 2016-06-23
        • 1970-01-01
        • 2014-10-29
        • 2011-03-10
        相关资源
        最近更新 更多