2009-12-05 12 views
7

Quali sono le migliori pratiche per archiviare set annidati (come alberi di commenti) in MongoDB?Set nidificati MongoDB

Voglio dire, ogni commento può avere un commento principale e commenti-bambini (risposte).

memorizzandoli in questo modo:

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

non è freddo, perché non possiamo, ad esempio, chiedere "tutti Inserisci vengono commentati da Peter" senza mappa/ridurre.

risposta

3

Penso che non ci sia una soluzione perfetta - dipende da quali operazioni sono più importanti per la tua app. Credo che Silicon Alley Insider memorizzi i commenti nidificati con MongoDB ad esempio. Ciò rende più difficile la domanda che hai citato.

Un'opzione è memorizzare al livello principale nel post un elenco di tutti i commentatori in un array. Pensa a ciò come dati denormalizzati. Quindi si possono facilmente trovare tutti i post che coinvolgono un certo commentatore. Quindi, per eseguire il drill down, utilizzare map/reduce o db.eval() per ottenere le informazioni del post annidate all'interno.

Un'altra nota: se si ha a che fare con un singolo documento, db.eval() è probabilmente più leggero di map/reduce. $ dove è anche un'opzione ma può essere lento quindi mi piace l'ulteriore 'lista di commentatori' menzionata sopra - non è anche facile indicizzare quella matrice (vedi 'Multikey' nei documenti).

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

2

Nel link dal post di dm Dwight Merriman menzioni utilizzando una chiave percorso e fare regex

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

Un altro modo per fare questo sarebbe stato con gli array

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

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

che dovrebbe renderlo abbastanza veloce.

se ogni nodo può essere solo in un unico percorso quindi non avrebbe bisogno di fare preoccuparsi di dove si trova nella lista

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

avrebbe trovato tutti figli di "a"

Invece dei nomi dei percorsi probabilmente utilizzerei _id dei nodi.

Aggiornamento

  • una cosa da stare attenti è che un indice può avere un solo array in esso.
  • Fare attenzione a spiegare le vostre domande

    db.test.trovare ({path: {$ in: [ "a", "b"]})

ti dà

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

ma

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

utilizza solo il primo elemento e quindi esegue la scansione di tutti i risultati corrispondenti per b.
Se a è l'elemento principale o si trova nella maggior parte dei record, si esegue una scansione quasi completa dei record anziché una query di indice efficiente.

Problemi correlati