문제
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" },
]
}
예를 들어, 우리는지도/축소없이 "Peter가 댓글을 달린 모든 게시물"을 요청할 수 없기 때문에 시원하지 않습니다.
해결책
완벽한 솔루션은 없다고 생각합니다. 앱에 어떤 작업이 더 중요한지에 따라 다릅니다. 예를 들어 Silicon Alley Insider는 Mongodb가 둥지를 틀고 있다고 생각합니다. 그것은 당신이 언급하는 쿼리를 더 어렵게 만듭니다.
한 가지 옵션은 게시물의 최상위 수준에서 배열의 모든 댓글 작성자 목록입니다. 그것을 비정규 화 된 데이터로 생각하십시오. 그런 다음 특정 주석 자와 관련된 모든 게시물을 쉽게 찾을 수 있습니다. 그런 다음 드릴 다운하면 MAP/READER 또는 DB.EVAL ()을 사용하여 중첩 된 게시물 정보를 가져옵니다.
또 하나의 메모 - 단일 문서를 다루는 경우 DB.eval ()은 아마도 MAP/Reduce보다 가벼운 체중 일 것입니다. $는 옵션이지만 느리게 할 수 있으므로 위에서 언급 한 추가 '주석 자 목록'이 마음에 들기 때문에 배열도 쉽게 인덱싱하는 것이 아닙니다 (문서의 '멀티 키리'참조).
다른 팁
DM의 Post Dwight Merriman의 링크에서 Path Key를 사용하고 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를 사용할 것입니다.
업데이트
- 조심해야 할 한 가지는 인덱스에 하나의 배열 만 가질 수 있다는 것입니다.
쿼리에 설명을 사용해보십시오
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가 루트 요소이거나 대부분의 레코드에있는 경우 효율적인 인덱스 쿼리 대신 레코드를 거의 완전히 스캔합니다.