2013-04-23 11 views
7

Ho un datastructure simile a questo:Usa interrogazione mangusta di ottenere solo un documento secondario

var GrandGrandChild = mongoose.Schema({ 
    attribute: String, 
    id: Number 
}); 

var GrandChild = mongoose.Schema({ 
    children: [GrandGrandChild], 
    id: Number, 
    irrelevantAttribute: String 
}); 

var Child = mongoose.Schema({ 
    children: [GrandChild], 
    id: Number, 
    irrelevantAttribute2: String 
}); 

var Parent = mongoose.Schema({ 
    children: [Child], 
    id: Number, 
    irrelevantAttribute3: String 
}); 

var GrandParent = mongoose.Schema({ 
    children: [Parent], 
    id: Number, 
    irrelevantAttribute4: String 
}); 

Queste sono un sacco di raccolte con documenti secondari in loro. Si noti che gli ID sono unici per i loro fratelli, ma non sono univoci per tutti gli elementi con quello stesso schema.

Così un nonno può avere un genitore con id 0, e un altro nonno può anche avere un genitore con id 0. ma un nonno non può avere 2 genitori con id 0.

L'unico schema che viene salvato è lo schema GrandParent e mongoose/mongodb crea un bel singolo documento di tutti i dati di questo nonno. (Esattamente quello che sto cercando)

Quindi, ecco il mio problema: ho un ID GrandParent, ID padre, ID figlio, GrandChildID e GrandGrandChild ID, e voglio in qualche modo ottenere solo l'oggetto GrandGrandChild a cui tutti questi ID stanno indicando.

Il modo brutto sarebbe, ma attualmente l'unico modo in cui riesco a mettermi al lavoro, è creare una query che ottiene questo grande documento di GrandParent e scorrere manualmente tutti gli array per trovare il Parent corretto, quindi ripetere il ciclo per trovare il bambino giusto, quindi loop di nuovo per trovare il nipote giusto, quindi loop ancora e trovare il grandgrandchild ho bisogno qui.

La mia domanda è, come faccio a comporre una query in mangusta che restituisce solo il documento grandgrandchild, o il documento grandparent con solo l'attributo children incluso, e in quanto attributo figli solo l'oggetto genitore incluso che si riferisce al bambino oggetto che si riferisce all'oggetto nipotino che fa riferimento all'oggetto grandgrandchild, permettendo il seguente con il risultato:

GRANDPARENT PARENT  CHILD  GRANDCHILD GRANDGRANDCHILD 
grandparent.children[0].children[0].children[0].children[0].attribute; 

Spero che qualcuno mi può aiutare su questa query, per quanto a dire che ho è questa:

GrandParentModel.findOne(
    { 
     "id" : 0, 
     "children.id" : 0, 
     "children.children.id" : 0, 
     "children.children.children.id" : 0, 
     "children.children.children.children.id" : 0 
    }, 
    {"children.children.children.children.$" : 1}, callback); 

Il problema con questa query è che i fratelli non affettuosi non sono stati tagliati.

Spero che qualcuno possa darmi una mano.

Hylke Bron

risposta

3

è passato un po 'di tempo da quando ho fatto questa domanda, ma penso di aver trovato un modo piuttosto elegante di lavorare con questo tipo di strutture.

In questo caso mostrerò come funziona solo con GrandParent, Parent e Child.

Invece di memorizzare un elenco di documenti secondari in ciascun documento (GrandParent.children, Parent.bambini), ho creato un identificatore univoco della seguente struttura:

Child.referenceId = { 
    grandparent: "some key to the grandparent of the parent", 
    parent: "some key to the parent", 
    child: "key of this child" 
}; 

Parent.referenceId = { 
    grandparent: "some key to its grandparent", 
    parent: "key of this parent" 
} 

GrandParent.referenceId = { 
    grandparent: "key of this parent" 
} 

Questo crea una gerarchia di Nonni> Parent> Bambino.

I modelli sarebbe qualcosa di simile al seguente:

var idStructure = { 
    grandparent: { type: String, required: true }, 
    parent: { type: String, required: false }, 
    child: { type: String, required: false } 
}; 

var GrandParent = mongoose.Schema({ 
    id: idStructure, 
    irrelevantAttribute: String 
}); 

var Parent = mongoose.Schema({ 
    id: idSructure, 
    irrelevantAttribute: String 
}); 

var Child = mongoose.Schema({ 
    id: idStructure, 
    irrelevantAttribute: String 
}); 

Si noti che un doesnt genitore sa direttamente il suo genitore, perché non vengono memorizzati come documenti secondari. Eppure c'è ancora una connessione tra Genitore e Bambino, attraverso il riferimento.

Durante la ricerca per tutta la FamilyTree di un nonno, si potrebbe semplicemente eseguire 3 query, e quindi collegare correttamente:

// First find all children which belong to the grandparent 
Child.find({"id.grandparent" : "some key to the grandparent"}) 
.exec(function(err, children) 
{ 
    if(err) 
     return; 

    Parent.find({"id.grandparent" : "some key to the grandparent"}) 
    .exec(function(err, parents) 
    { 
     if(err) 
      return; 

     // Loop through the parents and children to connect them before returning to a client 
     for(var i = 0; i < parents.length; i++) 
     { 
      var parent = parents[i]; 
      parent.children = []; 
      // loop through the children to check if they belong to the current parent 
      for(var j = 0; j < children.length; j++) 
      { 
       var child = children[j]; 
       if(parent.id.parent == child.id.parent) 
        parent.children.push(child); 
      } 
     } 

     // After filling the children into the parents, get the grandparents and do the same for the parents and grandparents as done for the children and parents. 
     GrandParent.find({"id.grandparent" : "some key to the grandparent"}) 
     .exec(function(err, grandparents) 
     { 
      // TODO: the same as done above (two loops, one loops the grandparents, other loops the parents 
      // Once this is finished, we have a filled grandparent 
     }); 

    }); 
}); 

Il codice di cui sopra si tradurrebbe in un solo nonno, riempita con i genitori, che sono pieno di bambini.

La ragione per cui non si trovano più nonni è perché l'ID del grandParent dovrebbe essere univoco, poiché il riferimento del nonno ha solo una proprietà di nonno.

Spero di aver chiarito il mio punto, perché attraverso questo metodo, si può facilmente cercare un bambino specifico, ottenere facilmente il suo genitore attraverso l'id di riferimento e il suo nonno anche attraverso l'id di riferimento.

Potrebbe essere un po 'complesso, ma una volta che si calcola il metodo per conto proprio, è tutto molto semplice.

Hylke

+0

Alcuni video rilevanti su youtube, uno su ["il principio di cardinalità minima"] (https://www.youtube.com/watch?v=L994ZiVuSTE) e l'altro con un esempio su [memorizzazione di dati gerarchici] (https :? //www.youtube.com/watch v = T5Yt6Ndm2QY). Questo è da un corso relativo a Mongoose su EDX chiamato ["Introduzione a MongoDB usando lo stack MEAN"] (https://courses.edx.org/courses/course-v1:MongoDBx+M101x+3T2015/info) –

2

è molto difficile ottenere questo tipo di cose funzionano in modo pulito.

Non ho trovato una soluzione pulita su questo argomento, ma forse posso aiutarti con la cosa in loop. È possibile evitare il loop utilizzando: var doc = parent.children.id (id); Finding a sub-document

Spero che questo ti aiuti. Cordiali saluti, Sebastian.

+0

Ma in questo caso ottengo grande primo documento, quindi seleziono da questo documento tutti i campi di cui ho bisogno. Piuttosto ottengo solo un piccolo documento secondario. Penso che lavorare con un piccolo documento sia più veloce, quindi lavorare con un grande documento. –

0

questo ha funzionato per me

 model.find({_id:args.id},{ commentList: { $elemMatch: { _id: todo.commentList[todo.commentList.length-1] } } },(err, todos) => { 
     if (err) reject(err) 
     else resolve(todos) 
     console.log(todos); 
     }) 

$elemMatch (projection)

Problemi correlati