Across documents you use the aggregation framework with $unwind and $group:
db.collection.aggregate([
// Match documents with the required criteria
{ "$match": { "charges.amount": 500 } },
// Unwind to de-normalize the content
{ "$unwind": "$charges" },
// Filter the de-normalized documents
{ "$match": { "charges.amount": 500 } },
// Group back the result
{ "$group": {
"_id": null,
"charges": { "$push": "$charges" }
}}
])
Or a bit more efficient in modern versions is to filter the array first:
db.collection.aggregate([
// Match documents with the required criteria
{ "$match": { "charges.amount": 500 } },
// Pre filter the array
{ "$redact": {
"$cond": {
"if": { "$eq": [{ "$ifNull": [ "$amount", 500 ] }, 500 ]},
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}},
// Unwind to de-normalize the content
{ "$unwind": "$charges" },
// Group back the result
{ "$group": {
"_id": null,
"charges": { "$push": "$charges" }
}}
])
Future versions ( working in current development releases ) will have a more helpful $filter method:
db.collection.aggregate([
// Match documents with the required criteria
{ "$match": { "charges.amount": 500 } },
// Filter the array
{ "$project": {
"charges": {
"$filter": {
"input": "$charges",
"as": "charge",
"cond": {
"$eq": [ "$$charge.amount", 500 ]
}
}
}
}},
// Unwind to de-normalize the content
{ "$unwind": "$charges" },
// Group back the result
{ "$group": {
"_id": null,
"charges": { "$push": "$charges" }
}}
])
All result in:
{
"_id": null,
"charges": [
{
amount: 500,
description: 'foo'
}, {
amount: 500,
description: 'foo'
}
]
}