Как фильтровать массив в поддокументе с помощью MongoDB [дубликат]
этот вопрос уже есть ответ здесь:
у меня есть массив в поддокументе, как это
{
"_id" : ObjectId("512e28984815cbfcb21646a7"),
"list" : [
{
"a" : 1
},
{
"a" : 2
},
{
"a" : 3
},
{
"a" : 4
},
{
"a" : 5
}
]
}
могу ли я фильтровать вложенный документ для A > 3
мой ожидаемый результат ниже
{
"_id" : ObjectId("512e28984815cbfcb21646a7"),
"list" : [
{
"a" : 4
},
{
"a" : 5
}
]
}
I попробуйте использовать $elemMatch
но возвращает первый соответствующий элемент в массиве
мой запрос:
db.test.find( { _id" : ObjectId("512e28984815cbfcb21646a7") }, {
list: {
$elemMatch:
{ a: { $gt:3 }
}
}
} )
результат возвращает один элемент в массиве
{ "_id" : ObjectId("512e28984815cbfcb21646a7"), "list" : [ { "a" : 4 } ] }
и я пытаюсь использовать агрегат с $match
но не работает
db.test.aggregate({$match:{_id:ObjectId("512e28984815cbfcb21646a7"), 'list.a':{$gte:5} }})
он возвращает все элементы в массиве
{
"_id" : ObjectId("512e28984815cbfcb21646a7"),
"list" : [
{
"a" : 1
},
{
"a" : 2
},
{
"a" : 3
},
{
"a" : 4
},
{
"a" : 5
}
]
}
могу ли я фильтровать элемент в массиве, чтобы получить результат как ожидаемый результат?
3 ответа:
используя
aggregate
- это правильный подход, но нужно$unwind
thelist
массив перед нанесением$match
так что вы можете фильтровать отдельные элементы, а затем использовать$group
чтобы собрать его обратно:db.test.aggregate( { $match: {_id: ObjectId("512e28984815cbfcb21646a7")}}, { $unwind: '$list'}, { $match: {'list.a': {$gt: 3}}}, { $group: {_id: '$_id', list: {$push: '$list.a'}}})
выходы:
{ "result": [ { "_id": ObjectId("512e28984815cbfcb21646a7"), "list": [ 4, 5 ] } ], "ok": 1 }
Обновление MongoDB 3.2
начиная с версии 3.2, вы можете использовать новый тег
$filter
оператор агрегации, чтобы сделать это более эффективно, только включаяlist
элементы, которые вы хотите во время$project
:db.test.aggregate([ { $match: {_id: ObjectId("512e28984815cbfcb21646a7")}}, { $project: { list: {$filter: { input: '$list', as: 'item', cond: {$gt: ['$$item.a', 3]} }} }} ])
выше решение работает лучше, если требуется несколько вложенных документов. $elemMatch также поставляется в очень использовать, если один соответствующий sub документ требуется в качестве вывода
db.test.find({list: {$elemMatch: {a: 1}}}, {'list.$': 1})
результат:
{ "_id": ObjectId("..."), "list": [{a: 1}] }
использовать фильтр$агрегации
выбирает подмножество массива для возврата на основе указанного состояние. Возвращает массив только с теми элементами, которые соответствуют состояние. Возвращенные элементы находятся в исходном порядке.
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 }} }} ]);