2009-12-05 139 views
7

在MongoDB中存储嵌套集(如注释树)的最佳实践是什么?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" }, 
    ] 
} 

是不冷静,因为我们不能,例如,索要无地图“它是由彼得·评论所有文章” /减少。

回答

3

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

一个选项是在顶层存储数组中所有评论者的列表。把它看作非规范化的数据。然后可以很容易地找到涉及某个评论者的所有帖子。然后深入研究,您可以使用map/reduce或db.eval()来获取嵌套的发布信息。另一个注意事项 - 如果你正在处理单个文档,db.eval()可能比map/reduce更轻。 $哪里也是一个选项,但速度可能会很慢,所以我喜欢上面提到的额外'评论者列表' - 也不容易索引该列表(请参阅文档中的'多键')。

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

2

在从DM的帖子德怀特·梅里曼链接提及使用路径密钥,做正则表达式匹配

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

另一种方式做,这将与阵列

{ 
    path : ["a", "b", "c", "d", "e", "f"] 
} 

db.test.ensureIndex({path: 1}) 

应该让它变得非常快。

如果每个节点只能在单一路径,那么你就不需要做一下它位于列表

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

担心会找到的“一”

所有儿童我可能会使用节点的_id,而不是路径名。

更新

  • 一件事要小心的是,指数只能在它一个阵列。
  • 小心使用说明您的查询

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