2013-05-30 19 views
25

Mi sono appena bloccato con questo problema. Ho due schemi Mongoose:Mongoose - ricerca di documenti secondari in base ai criteri

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

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

domanda è, come per andare a prendere tutti i documenti secondari (in questo caso, childrenSchema oggetti) da ogni documento padre? Supponiamo che ho un po 'di dati:

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

Vorrei recuperare - in una singola query - tutti i bambini di età superiore a 18. E' possibile? Ogni risposta sarà apprezzata, grazie!

+0

vuoi che solo restituire il genitore se il bambino è più di 18 anni o vuoi per popolare solo i bambini che hanno più di 18 anni su ciascun genitore? –

+0

Sarebbe bello se ricevessi il set di "bambini" ... –

risposta

38

È possibile utilizzare $elemMatch come un operatore di query proiezione nelle più recenti versioni MongoDB. Dalla shell mongo:

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

Questo consente di filtrare i documenti dei bambini più piccoli fuori della matrice children:

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

Come si può vedere, i bambini sono ancora raggruppati all'interno delle loro documenti genitore. Le query MongoDB restituiscono documenti dalle raccolte. È possibile utilizzare il metodo del quadro di aggregazione $unwind a dividerli in documenti separati:

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

ripeto la clausola di $match per le prestazioni: la prima volta attraverso elimina i genitori con senza bambini di almeno 18 anni di età, in modo che il $unwind considera solo documenti utili. Il secondo $match rimuove l'output $unwind non corrispondente e lo strumento $project solleva le informazioni dei bambini dai documenti secondari al livello principale.

+0

Grazie, controllerò :) –

+0

Funziona! :) Grazie per l'aiuto! :) Dove posso ottenere alcuni documenti sulle operazioni avanzate di MongoDB? I suoi documenti sono abbastanza? Desidero imparare il più possibile su MongoDB :) –

+1

Prendere la classe MongoDB per gli sviluppatori online di 10gen, leggi il libro MongoDB Design Patterns di Rick Copeland. –

16

In Mangusta, è anche possibile utilizzare l'elegante .populate() funzione come questa:

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

'populate' funziona quando si fa riferimento a documenti in altre raccolte . L'OP sta utilizzando i documenti secondari. – Lulylulu

+0

E 'passato molto tempo da quando ho fatto questa risposta :) e non posso provarlo ora, ma penso che dovrebbe funzionare anche per i documenti embedded! – AbdelHady

Problemi correlati