質問
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" },
]
}
たとえば、「ピーターによってコメントされているすべての投稿」をマップ/削減せずに求めることはできないため、クールではありません。
解決
完璧な解決策はないと思います - アプリにとってどの操作がより重要であるかによって異なります。たとえば、Mongodbにネストされたコメントのコメントがシリコンアレイインサイダーコメントだと思います。それはあなたが言及するクエリをより難しくします。
1つのオプションは、アレイ内のすべてのコメンターのリストを投稿のトップレベルに保存することです。それは非正規化データと考えてください。その後、特定のコメンターを含むすべての投稿を簡単に見つけることができます。次に、ドリルダウンするには、Map/Reduceまたはdb.eval()を使用して、ネストされた投稿情報を内部に取得します。
もう1つのメモ - 単一のドキュメントを扱っている場合、db.eval()はおそらくMAP/reduceよりも軽量です。 $もオプションですが、遅いこともあるので、上記の追加の「コメンターのリスト」が好きです - その配列も簡単にインデックスすることはできません(ドキュメントの「マルチケイ」を参照)。
他のヒント
DMのポストDwight Merrimanのリンクでは、パスキーを使用してRegex Matchesを実行することに言及しています
{
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を使用します。
アップデート
- 注意すべきことの1つは、インデックスに1つの配列しか持てないことです。
クエリで説明するように注意してください
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があなたのルート要素であるか、ほとんどのレコードにある場合、効率的なインデックスクエリではなく、レコードをほぼ完全にスキャンしています。