Sí, hay dos maneras de hacer esto. Entonces puede usar $elemMatch
en el lado de la proyección como ya tienes, con ligeros cambios:
Model.findById(id,
{ "comments": { "$elemMatch": {"created.by": "Jane" } } },
function(err,doc) {
O simplemente agregue a la parte de consulta y use el $
posicional operador:
Model.findOne(
{ "_id": id, "comments.created.by": "Jane" },
{ "comments.$": 1 },
function(err,doc) {
Cualquiera de las dos formas es perfectamente válida.
Si quería algo un poco más complicado que eso, puede usar .aggregate()
$project
operador en su lugar:
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) {
Por lo tanto, el marco de agregación se puede usar para mucho más que simplemente agregar resultados. Es $project
El operador le brinda más flexibilidad de la que está disponible para la proyección usando .find()
. También le permite filtrar y devolver múltiples resultados de matrices, algo que tampoco se puede hacer con la proyección en .find()
.