Oui, il y a deux façons de procéder. Vous pouvez donc soit utiliser le $elemMatch
côté projection comme vous l'avez déjà fait, avec de légères modifications :
Model.findById(id,
{ "comments": { "$elemMatch": {"created.by": "Jane" } } },
function(err,doc) {
Ou ajoutez simplement à la partie requête et utilisez le $
positionnel opérateur :
Model.findOne(
{ "_id": id, "comments.created.by": "Jane" },
{ "comments.$": 1 },
function(err,doc) {
L'une ou l'autre manière est parfaitement valable.
Si vous vouliez quelque chose d'un peu plus compliqué que cela, vous pouvez utiliser le .aggregate()
méthode et c'est $project
opérateur à la place :
Model.aggregate([
// Still match the document
{ "$match": "_id": id, "comments.created.by": "Jane" },
// Unwind the array
{ "$unwind": "$comments" },
// Only match elements, there can be more than 1
{ "$match": "_id": id, "comments.created.by": "Jane" },
// Project only what you want
{ "$project": {
"comments": {
"body": "$comments.body",
"by": "$comments.created.by"
}
}},
// Group back each document with the array if you want to
{ "$group": {
"_id": "$_id",
"comments": { "$push": "$comments" }
}}
],
function(err,result) {
Ainsi, le cadre d'agrégation peut être utilisé pour bien plus que simplement agréger des résultats. C'est $project
l'opérateur vous donne plus de flexibilité que ce qui est disponible pour la projection en utilisant .find()
. Il vous permet également de filtrer et de renvoyer plusieurs résultats de tableau, ce qui est également quelque chose qui ne peut pas être fait avec la projection dans .find()
.