代码之家  ›  专栏  ›  技术社区  ›  Valentin Golev

MongoDB嵌套集

  •  7
  • Valentin Golev  · 技术社区  · 15 年前

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

    我的意思是,每个评论都可以有家长评论和孩子评论(答案)。

    像这样存储它们:

    {
       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" },
       ]
    }
    

    不酷,因为我们不能,例如,在没有地图/减少的情况下,要求“所有由彼得评论的帖子”。

    2 回复  |  直到 9 年前
        1
  •  3
  •   dm.    15 年前

    我认为没有完美的解决方案-取决于什么操作对你的应用程序更重要。例如,我相信硅谷的内部商店评论嵌套在MongoDB中。这确实使您提到的查询更加困难。

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

    另一个注意事项是,如果处理单个文档,db.eval()可能比map/reduce轻。$where也是一个选项,但速度可能很慢,所以我喜欢上面提到的附加“注释列表”——不是也很容易索引该数组(参见文档中的“multikey”)。

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

        2
  •  2
  •   Pete Brumm    13 年前

    在dm的文章dwight-meriman的链接中提到使用路径键和执行regex匹配

    {
      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(路径:$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是根元素或者在大多数记录中,那么您将对记录进行几乎完全扫描,而不是进行有效的索引查询。