Use "dot notation":
Post.find(
{
_id: req.params.id,
"commments": { "$exists": true },
"comments.status": 1
},
function (err, data) {
if (err) return console.error(err);
return res.json(data);
}
);
Without that you are asking for comments to be "exactly" in the form you are querying and only contain "status" as a field.
If all you want to return are just the matching comments of an array you basically have two options.Either you use the positional $
operator in order to return only the first matching element of an array, which is it's current restriction. Or you use the aggregation framework in order to return all of the items:
Post.aggregate(
[
// Initial match is on only the documents that contain
{ "$match": {
"_id": req.params.id,
"comments": { "$exists": true },
"comments.status": 1
}},
// Unwind the array to "de-normalize" as documents
{ "$unwind": "$comments" },
// Match the "unwound" documents
{ "$match": {
"comments.status": 1
}},
// Push back as an array
{ "$group": {
"_id": "$_id",
"title": { "$first": "$title },
"post": { "$first": "$post" },
"comments": { "$push": "$comments" }
}}
],
function(err,data) {
// work in here
})
Or with MongoDB 2.6 and upwards you can do that "in-place" using $map
instead:
Post.aggregate(
[
// Initial match is on only the documents that contain
{ "$match": {
"_id": req.params.id,
"comments": { "$exists": true },
"comments.status": 1
}},
// Project matching items only
{ "$project": {
"title": 1,
"post": 1,
"comments": {
"$setDifference": [
{
"$map": {
"input": "$comments",
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el.status", 1 ] },
"$$el",
false
]
}
}
},
[false]
]
}
}}
],
function(err,data) {
// work in here
})
So the difference here is matching the "document" that contains the conditions you specify in the query and "filtering" the array members that only match the specification of your query.