Reputation: 53
I have a document structured like this:
{
"_id" : ObjectId("564d2702d4c68225cb00726f"),
"list" : [
{
"a" : NumberInt(1),
"test" : "public"
},
{
"a" : NumberInt(2),
"test" : "public"
},
{
"a" : NumberInt(3),
"test" : "public"
},
{
"a" : NumberInt(4),
"test" : "public"
},
{
"a" : NumberInt(5),
"test" : "public"
}
],
"other_fields": ""}
Can I filter subdocument for a in (1, 5)
My expect result below
{
"_id" : ObjectId("564d2702d4c68225cb00726f"),
"list" : [
{
"a" : NumberInt(1),
"test" : "public"
},
{
"a" : NumberInt(5),
"test" : "public"
}
]}
I try to use $elemMatch
, but when I use $in
, an error happened.
Upvotes: 4
Views: 967
Reputation: 61225
Starting from MongoDB 3.2, we can use the $filter
operator to efficiently to this. In $filter
's conditional expression we need to use the $setIsSubset
operator to check if a given value is in the array. This is mainly because we can't use the $in
query operator in the the $project
stage.
db.collection.aggregate([
{ "$project": {
"list": {
"$filter": {
"input": "$list",
"as": "lst",
"cond": { "$setIsSubset": [ [ "$$lst.a" ], [ 1, 5 ] ] }
}
}
}}
])
From MongoDB 3.0.x backwards you need a different, less efficient approach using the $map
operator the and the $setDifference
operator.
db.collection.aggregate([
{ "$project": {
"list": {
"$setDifference": [
{ "$map": {
"input": "$list",
"as": "lst",
"in": {
"$cond": [
{ "$setIsSubset": [ [ "$$lst.a" ], [ 1, 5 ] ] },
"$$lst",
false
]
}
}},
[false]
]
}
}}
])
Upvotes: 3
Reputation: 2766
Try following query:-
db.collection.aggregate([
{
"$match": {
$or[{ "list.a": NumberInt(1)}, {{ "list.a": NumberInt(5)}}]
}
},
{
"$project": {
"list": {
"$setDifference": [
{
"$map": {
"input": "$list",
"as": "o",
"in": {
"$cond": [
{
$or[{ "list.a": NumberInt(1)},
{{ "list.a": NumberInt(5)}}]
},
"$$o",
false
]
}
}
},
[false]
]
}
}
}
])
By using the query result will be:-
{
"_id" : ObjectId("564d2702d4c68225cb00726f"),
"list" : [
{
"a" : NumberInt(1),
"test" : "public"
},
{
"a" : NumberInt(5),
"test" : "public"
}
]}
Upvotes: 0