I will use the example from here
{
_id: 1,
zipcode: 63109,
students: [
{ name: \"john\", school: 102, age: 10 },
{ name: \"je
In order to return multiple subdocuments, you're going to need to use the aggregation framework. This will return all of the subdocuments you're looking for:
db.zip.aggregate(
{$match: {zipcode: 63109}},
{$unwind: "$students"},
{$match: {"students.school": 102}}
)
You can do various things to get different output, but this will return:
{
"result" : [
{
"_id" : 1,
"zipcode" : 63109,
"students" : {
"name" : "john",
"school" : 102,
"age" : 10
}
},
{
"_id" : 1,
"zipcode" : 63109,
"students" : {
"name" : "jess",
"school" : 102,
"age" : 11
}
},
{
"_id" : 4,
"zipcode" : 63109,
"students" : {
"name" : "barney",
"school" : 102,
"age" : 7
}
}
],
"ok" : 1
}
This worked for me in a case of similar filtering. Now I know this question was asked many years ago, but to anyone looking for an answer like me. here's what worked for me. Thanks to original answer!
In the case of this particular question:
outerparam is zipcode and innerarray.property is students.school.
let cursor = db
.collection("somecollection")
.aggregate(
{ $match: { outerparam: outermatch } },
{ $unwind: "$innerarray" },
{ $match: { "innerarray.property": propertymatch } },
{ $project: { "innerarray.$": 1 } });
Previous and incorrect answer:
This should work as of today. See https://docs.mongodb.com/v3.2/reference/operator/projection/positional/#array-field-limitations
You should get the correct result when querying using $elemMatch in the query and exposing the sub-document in the projection like following:
db.schools.find( { zipcode: 63109, students: { $elemMatch: { school: 102 } } },
{ 'students.$': 1 } )
New answer
Limiting the list of sub-documents to those matching the query is as of now not possible using find(). Please take aggregate() instead or take one of the following possibilities:
You could either get all the sub-documents of the matching document by adding the array-property in the projection:
db.schools.find( { zipcode: 63109, students: { $elemMatch: { school: 102 } } }, { 'students': 1 })
> { "_id" : 1, "students" : [ { "name" : "john", "school" : 102, "age" : 10 }, { "name" : "jess", "school" : 102, "age" : 11 }, { "name" : "jeff", "school" : 108, "age" : 15 } ] }
> { "_id" : 4, "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }
Or you can get the first item matching the $elemMatch query on the sub-documents:
db.schools.find( { zipcode: 63109, students: { $elemMatch: { school: 102 } } }, { 'students.$': 1 })
> { "_id" : 1, "students" : [ { "name" : "john", "school" : 102, "age" : 10 } ] }
> { "_id" : 4, "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }