如何使用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]
        
    
])

【讨论】:

聚合操作是修改文档还是只进行选择? @Cherif aggregate 不会影响文档本身。 如果您想将该查询的结果发布给客户端,您会怎么做? 此解决方案是否利用数组元素内部的索引(如果数组元素本身就是一个文档)?假设在数组元素的某个路径上有一个索引。 使用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过滤子文档中的数组[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何匹配MongoDB中的子文档数组?

如何使用 C# 驱动程序更新 MongoDB 数组中的子文档

如何使用C#驱动程序更新MongoDB数组中的子文档

如何使用Mongoose和MongoDB 2.6插入子文档中数组中的特定位置

如何使用Mongoose和MongoDB 2.6插入子文档中数组中的特定位置

在 Mongoose/MongoDB 的文档中过滤数组、子文档、数组、文档