Sim, existem duas maneiras de fazer isso. Então você pode usar o
$elemMatch
no lado da projeção como você já tem, com pequenas alterações:Model.findById(id,
{ "comments": { "$elemMatch": {"created.by": "Jane" } } },
function(err,doc) {
Ou apenas adicione à parte da consulta e use o
$
posicional operador:Model.findOne(
{ "_id": id, "comments.created.by": "Jane" },
{ "comments.$": 1 },
function(err,doc) {
Qualquer uma das formas é perfeitamente válida.
Se você queria algo um pouco mais complicado do que isso, você pode usar o
.aggregate()
e é $project
operador em vez disso: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) {
Portanto, a estrutura de agregação pode ser usada para muito mais do que simplesmente agregar resultados. É
$project
operador lhe dá mais flexibilidade do que está disponível para projeção usando .find()
. Ele também permite filtrar e retornar vários resultados de array, o que também não pode ser feito com projeção em .find()
.