Mongoose – recherche de sous-documents par critère

Je viens de me retrouver avec ce problème. J’ai deux schémas Mongoose:

var childrenSchema = mongoose.Schema({ name: { type: Ssortingng }, age: { type: Number, min: 0 } }); var parentSchema = mongoose.Schema({ name : { type: Ssortingng }, children: [childrenSchema] }); 

La question est, comment récupérer tous les sous-documents (dans ce cas, les objects childrenSchema ) de chaque document parent? Supposons que j’ai des données:

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

Je voudrais récupérer – en une seule requête – tous les enfants de plus de 18 ans. Est-ce possible? Chaque réponse sera appréciée, merci!

Vous pouvez utiliser $elemMatch tant qu’opérateur de projection de requête dans les versions les plus récentes de MongoDB. De la coquille de mongo:

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

Ceci filtre les documents des plus jeunes enfants du tableau des children :

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

Comme vous pouvez le constater, les enfants sont toujours regroupés dans leurs documents parents. Les requêtes MongoDB renvoient des documents à partir de collections. Vous pouvez utiliser la méthode $unwind du framework d’agrégation pour les scinder en documents distincts:

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

Je répète la clause $match pour l’exécution: la première fois, elle élimine les parents sans enfant de 18 ans au moins, de sorte que le $unwind ne considère que les documents utiles. La deuxième $match supprime la sortie $unwind qui ne correspond pas et le $project extrait les informations relatives aux enfants des sous-documents au niveau supérieur.

En Mongoose, vous pouvez également utiliser la fonction élégante .populate() comme ceci:

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