2013-05-30 9 views
25

Po prostu utknąłem z tym problemem. Mam dwa Mongoose schematów:Mongoose - znalezienie poddokumentów według kryteriów

var childrenSchema = mongoose.Schema({ 
    name: { 
     type: String 
    }, 
    age: { 
     type: Number, 
     min: 0 
    } 
}); 

var parentSchema = mongoose.Schema({ 
    name : { 
     type: String 
    }, 
    children: [childrenSchema] 
}); 

Pytanie jest, jak pobrać wszystkie Dokumenty podrzędne (w tym przypadku childrenSchema obiektów) z każdego dokumentu nadrzędnego? Załóżmy, że mam pewne dane:

var parents = [ 
    { name: "John Smith", 
    children: [ 
     { name: "Peter", age: 2 }, { name: "Margaret", age: 20 } 
    ]}, 
    { name: "Another Smith", 
    children: [ 
     { name: "Martha", age: 10 }, { name: "John", age: 22 } 
    ]} 
]; 

Chciałbym odzyskać - w jednym zapytaniu - wszystkie dzieci starsze niż 18. Czy to możliwe? Każda odpowiedź zostanie doceniona, dzięki!

+0

Czy chcesz go zwrócić tylko rodzica, gdy dziecko ma skończone 18 lat lub chcesz go tylko wypełnić dzieciom, że mają ponad 18 lat na każdego rodzica? –

+0

Byłoby wspaniale, gdybym dostał zestaw "dzieci" ... –

Odpowiedz

38

Możesz użyć $elemMatch jako operatora projekcji zapytań w najnowszych wersjach MongoDB. Z powłoki Mongo:

db.parents.find(
    {'children.age': {$gte: 18}}, 
    {children:{$elemMatch:{age: {$gte: 18}}}}) 

ten filtruje dokumenty młodszych dzieci z tablicy children:

{ "_id" : ..., "children" : [ { "name" : "Margaret", "age" : 20 } ] } 
{ "_id" : ..., "children" : [ { "name" : "John", "age" : 22 } ] } 

Jak widać, dzieci nadal są pogrupowane w ich dokumentach nadrzędnych. Zapytania MongoDB zwracają dokumenty z kolekcji. Można użyć $unwind metody przyjęte w ramach agregacji, aby podzielić je na oddzielnych dokumentach:

> db.parents.aggregate({ 
    $match: {'children.age': {$gte: 18}} 
}, { 
    $unwind: '$children' 
}, { 
    $match: {'children.age': {$gte: 18}} 
}, { 
    $project: { 
     name: '$children.name', 
     age:'$children.age' 
    } 
}) 
{ 
    "result" : [ 
     { 
      "_id" : ObjectId("51a7bf04dacca8ba98434eb5"), 
      "name" : "Margaret", 
      "age" : 20 
     }, 
     { 
      "_id" : ObjectId("51a7bf04dacca8ba98434eb6"), 
      "name" : "John", 
      "age" : 22 
     } 
    ], 
    "ok" : 1 
} 

Powtarzam klauzuli $match dla usług: pierwszy raz przez to eliminuje rodzicom bez dzieci co najmniej 18 lat, a więc $unwind uwzględnia tylko przydatne dokumenty. Drugi $match usuwa dane wyjściowe, które nie pasują, a informacje o dzieciach z subdokumentów na najwyższy poziom.

+0

Dzięki, sprawdzę to :) –

+0

To działa! :) Dzięki za pomoc! :) Gdzie mogę uzyskać dokumentację na temat zaawansowanych operacji MongoDB? Jego dokumenty są wystarczające? Chciałbym dowiedzieć się jak najwięcej o MongoDB :) –

+1

Weź udział w klasie online MongenDB dla programistów klasy 10gen, przeczytaj książkę MongoDB Design Patterns autorstwa Ricka Copelanda. –

16

W Mangusta, można również skorzystać z elegancką .populate() funkcję tak:

parents 
.find({}) 
.populate({ 
    path: 'children', 
    match: { age: { $gte: 18 }}, 
    select: 'name age -_id' 
}) 
.exec() 
+1

'populate' działa podczas porównywania dokumentów w innych kolekcjach . OP używa subdokumentów. – Lulylulu

+0

To długo, odkąd udzieliłem tej odpowiedzi :) i nie mogę tego teraz wypróbować, ale myślę, że powinna działać również dla wbudowanych dokumentów! – AbdelHady

Powiązane problemy