Solución:
Utilizando aggregate
es el enfoque correcto, pero necesita $unwind
los list
matriz antes de aplicar el $match
para que pueda filtrar elementos individuales y luego usar $group
para volver a armarlo:
db.test.aggregate([
{ $match: {_id: ObjectId("512e28984815cbfcb21646a7")}},
{ $unwind: '$list'},
{ $match: {'list.a': {$gt: 3}}},
{ $group: {_id: '$_id', list: {$push: '$list.a'}}}
])
salidas:
{
"result": [
{
"_id": ObjectId("512e28984815cbfcb21646a7"),
"list": [
4,
5
]
}
],
"ok": 1
}
MongoDB 3.2 Actualización
A partir de la versión 3.2, puede utilizar la nueva $filter
operador de agregación para hacer esto de manera más eficiente al incluir solo el list
elementos que desea durante un $project
:
db.test.aggregate([
{ $match: {_id: ObjectId("512e28984815cbfcb21646a7")}},
{ $project: {
list: {$filter: {
input: '$list',
as: 'item',
cond: {$gt: ['$$item.a', 3]}
}}
}}
])
La solución anterior funciona mejor si se requieren varios subdocumentos coincidentes. $ elemMatch también es muy útil si se requiere un único subdocumento coincidente como salida
db.test.find({list: {$elemMatch: {a: 1}}}, {'list.$': 1})
Resultado:
{
"_id": ObjectId("..."),
"list": [{a: 1}]
}
Usar agregación de $ filter
Selecciona un subconjunto de la matriz para devolver según la condición especificada. Devuelve una matriz con solo aquellos elementos que coinciden con la condición. Los elementos devueltos están en el orden original.
db.test.aggregate([
{$match: {"list.a": {$gt:3}}}, // <-- match only the document which have a matching element
{$project: {
list: {$filter: {
input: "$list",
as: "list",
cond: {$gt: ["$$list.a", 3]} //<-- filter sub-array based on condition
}}
}}
]);