I've just got stuck with this problem. I've got two Mongoose schemas:
var childrenSchema = mongoose.Schema({
name: {
type: String
},
age: {
type: Number,
min: 0
}
});
var parentSchema = mongoose.Schema({
name : {
type: String
},
children: [childrenSchema]
});
Question is, how to fetch all subdocuments (in this case, childrenSchema
objects) from every parent document? Let's suppose I have some data:
var parents = [
{ name: "John Smith",
children: [
{ name: "Peter", age: 2 }, { name: "Margaret", age: 20 }
]},
{ name: "Another Smith",
children: [
{ name: "Martha", age: 10 }, { name: "John", age: 22 }
]}
];
I would like to retrieve - in a single query - all children older than 18. Is it possible? Every answer will be appreciated, thanks!
A. Jesse Jiryu Davis's response works like a charm, however for later versions of Mongoose (Mongoose 5.x) we get the error:
Mongoose 5.x disallows passing a spread of operators to
Model.aggregate()
. Instead ofModel.aggregate({ $match }, { $skip })
, doModel.aggregate([{ $match }, { $skip }])
So the code would simply now be:
(note the array brackets around the queries)
Hope this helps someone!
In Mongoose, you can also use the elegant
.populate()
function like this:You can use
$elemMatch
as a query-projection operator in the most recent MongoDB versions. From the mongo shell:This filters younger children's documents out of the
children
array:As you can see, children are still grouped inside their parent documents. MongoDB queries return documents from collections. You can use the aggregation framework's
$unwind
method to split them into separate documents:I repeat the
$match
clause for performance: the first time through it eliminates parents with no children at least 18 years old, so the$unwind
only considers useful documents. The second$match
removes$unwind
output that doesn't match, and the$project
hoists children's info from subdocuments to the top level.