2013-04-23 33 views
7

Ich habe ein ähnliches Datenstruktur wie folgt aus:Verwenden Mungo Abfrage erhalten nur eine Subdokument

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 
}); 

Dies sind viele Sammlungen mit Subdokumente in ihnen. Beachten Sie, dass die IDs für ihre Geschwister eindeutig sind, aber nicht für alle Elemente mit demselben Schema eindeutig sind.

So ein großartiger Elternteil kann einen Elternteil mit der ID 0 hat und eineine andere Großeltern können auch einen Elternteil mit der ID 0 haben aber ein Großelternteil kann nicht mit 2 Eltern mit der ID 0.

Das einzigen Schema, das gespeichert wird ist das GrandParent-Schema, und Mungo/Mongodb macht ein schönes großes einzelnes Dokument aller Daten dieses Großelternteils. (Genau das, was ich suche)

Also hier ist mein Problem: Ich habe eine GrandParent ID, Eltern ID, Kind ID, GrandChildID und GrandGrandChild ID, und ich möchte irgendwie nur das GrandGrandChild-Objekt, das alle diese IDs zeigen. Der hässliche Weg wäre, aber zur Zeit der einzige Weg, ich kann zur Arbeit zu kommen, ist eine Abfrage, die dieses große Dokument von GrandParent, und manuell durchlaufen alle Arrays, um das richtige Elternteil zu finden, dann erneut zu machen um das richtige Kind zu finden, dann wiederholen Sie die Schleife, um das richtige Enkelkind zu finden, dann wiederholen Sie die Schleife und finden Sie den Urenkel, der hier gebraucht wird.

Meine Frage ist, wie würde ich eine Abfrage in Mungo, die entweder nur das Grandgrandchild-Dokument, oder das Großelterndokument mit nur die Children-Attribut enthalten enthalten, und in diesem Children-Attribut nur das Elternobjekt enthalten, die auf das Kind verweist enthalten Objekt, das dem Enkel Objekt verweist, die auf das grandgrandchild Objekt bezieht, das folgende mit dem Ergebnis, so dass:

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

ich hoffe jemand mich auf diese Abfrage helfen kann, wie weit ist ich erhielt, ist dies:

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); 

Das Problem mit dieser Abfrage besteht darin, dass die nicht jugendfreien Geschwister nicht entfernt wurden.

Ich hoffe, dass mir jemand helfen kann.

Hylke Bron

Antwort

3

Es ist schon eine Weile her, dass ich diese Frage gestellt habe, aber ich denke, dass ich eine ziemlich elegante Art gefunden habe, mit solchen Strukturen zu arbeiten.

In diesem Fall werde ich zeigen, wie es nur mit GrandParent, Parent und Child funktioniert.

Anstatt eine Liste der Filialdokumente in jedem Dokument zu speichern (GrandParent.children, Parent.Kinder), habe ich eine eindeutige Kennung der folgenden Struktur:

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

Dies schafft eine Hierarchie von Großeltern> Parent> Child.

Die Modelle würden in etwa wie folgt sein:

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 
}); 

Beachten Sie, dass ein Elternteil tut direkt seine Eltern wissen, denn sie sind als Subdokumente nicht gespeichert werden. Dennoch gibt es immer noch eine Verbindung zwischen Eltern und Kind durch die referenceId.

Wenn für die ganze familytree eines Großeltern suchen, würde man einfach 3-Abfragen ausführen und sie dann richtig anschließen:

// 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 
     }); 

    }); 
}); 

Der obige Code in nur einem Großeltern führen würde, mit den Eltern gefüllt, das sind mit Kindern gefüllt.

Der Grund, warum keine Großeltern mehr gefunden werden, ist, weil die ID des grandParents eindeutig sein sollte, denn die referenceId des Großelternteils hat nur eine Großelterneigenschaft.

Ich hoffe, ich habe meinen Punkt klar gemacht, weil durch diese Methode kann man leicht nach einem bestimmten Kind suchen, leicht erhalten seine Eltern durch die Referenz-ID und seine Großeltern auch durch die Referenz-ID.

Es könnte ein bisschen komplex sein, aber sobald Sie die Methode für sich selbst herausfinden, ist alles irgendwie geradlinig.

Hylke

+0

Einige relevante Videos auf youtube, eine auf ["das Prinzip der geringsten Kardinalität"] (https://www.youtube.com/watch?v=L994ZiVuSTE) und die andere mit einem Beispiel auf [Speicherung hierarchischer Daten] (https : //www.youtube.com/watch? v = T5Yt6Ndm2QY). Dies ist von einem Mongoose-bezogenen Kurs auf EDX namens ["Einführung in MongoDB mit dem MEAN-Stack"] (https://courses.edx.org/courses/course-v1:MongoDBx+M101x+3T2015/info) –

2

ist sehr schwierig, diese Art zu erhalten Dinge in einer sauberen Art und Weise arbeiten.

Ich habe keine saubere Lösung zu diesem Thema gefunden, aber vielleicht kann ich Ihnen mit dem Looping-Ding helfen. Sie können die Schleife vermeiden mit: var doc = parent.children.id (id); Finding a sub-document

Ich hoffe, das hilft Ihnen. Grüße, Sebastian.

+0

Aber in diesem Fall habe ich erste große Dokument bekommen, dann habe ich aus diesem Dokument auswählen alle Felder, die ich brauche. Eher bekomme ich nur ein kleines Filialdokument. Ich denke, dass Arbeit mit kleinen Dokumenten schneller ist als mit großen Dokumenten. –

0

dies funktionierte für mich

 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)

Verwandte Themen