在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" },
]
}
并不酷,因为我们不能在没有map / reduce的情况下要求“所有由Peter评论的帖子”。
答案 0 :(得分:3)
我认为没有完美的解决方案 - 取决于哪些操作对您的应用更重要。我相信Silicon Alley Insider存储了与MongoDB嵌套的注释。这确实使你提到的查询更难。
一个选项是在帖子的顶层存储数组中所有评论者的列表。将其视为非规范化数据。然后,人们可以轻松找到涉及某个评论者的所有帖子。然后向下钻取,使用map / reduce或db.eval()来获取嵌套的帖子信息。
另一个注意事项 - 如果您正在处理单个文档,则db.eval()可能比map / reduce更轻。 $ where也是一个选项,但可能很慢,所以我喜欢上面提到的额外“评论者列表” - 也不容易索引该数组(参见文档中的“Multikey”)。
答案 1 :(得分: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是你的根元素或者是你的大多数记录,那么你几乎完全扫描记录而不是有效的索引查询。