如何使用MongoDB过滤子文档中的数组[重复]
Posted
技术标签:
【中文标题】如何使用MongoDB过滤子文档中的数组[重复]【英文标题】:How to filter array in subdocument with MongoDB [duplicate] 【发布时间】:2013-02-13 13:14:21 【问题描述】:我在子文档中有这样的数组
"_id" : ObjectId("512e28984815cbfcb21646a7"),
"list" : [
"a" : 1
,
"a" : 2
,
"a" : 3
,
"a" : 4
,
"a" : 5
]
我可以为 > 3 过滤子文档
下面是我的预期结果
"_id" : ObjectId("512e28984815cbfcb21646a7"),
"list" : [
"a" : 4
,
"a" : 5
]
我尝试使用$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
]
我可以过滤数组中的元素以获得预期结果吗?
【问题讨论】:
【参考方案1】:使用aggregate
是正确的方法,但是您需要在应用$match
之前将$unwind
list
数组,以便您可以过滤单个元素,然后使用$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
聚合运算符更有效地执行此操作,只需在 $project
中包含您想要的 list
元素:
db.test.aggregate([
$match: _id: ObjectId("512e28984815cbfcb21646a7"),
$project:
list: $filter:
input: '$list',
as: 'item',
cond: $gt: ['$$item.a', 3]
])
【讨论】:
聚合操作是修改文档还是只进行选择? @Cherifaggregate
不会影响文档本身。
如果您想将该查询的结果发布给客户端,您会怎么做?
此解决方案是否利用数组元素内部的索引(如果数组元素本身就是一个文档)?假设在数组元素的某个路径上有一个索引。
使用cond: $eq: ['$$item.a', <value> ]
根据精确的等效值过滤元素。【参考方案2】:
使用$filter aggregation
根据指定选择要返回的数组子集 健康)状况。返回一个仅包含与 健康)状况。返回的元素按照原来的顺序排列。
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
]);
【讨论】:
请注意,如果您使用的是Atlas,则$filter
不能用于免费层。【参考方案3】:
如果需要多个匹配的子文档,上述解决方案效果最佳。 如果需要单个匹配的子文档作为输出,$elemMatch 也非常有用
db.test.find(list: $elemMatch: a: 1, 'list.$': 1)
结果:
"_id": ObjectId("..."),
"list": [a: 1]
【讨论】:
这对我来说是最好的解决方案。但是第二个参数仅适用于原始类型。由于我在数组中有一个对象,我的解决方案是:ShoppingCartModel.findOne("_id": ctx.params.idCart, "active" : true, products: $elemMatch : "products.active" : true)
(我只过滤活动:真正的购物车和产品)以上是关于如何使用MongoDB过滤子文档中的数组[重复]的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 C# 驱动程序更新 MongoDB 数组中的子文档
如何使用Mongoose和MongoDB 2.6插入子文档中数组中的特定位置