使用mongodb中的聚合获取具有最大值的所有文档

5 mongodb mongodb-query aggregation-framework

我想获取具有特定字段的最高值而不是另一个字段的组的"所有文档".

考虑以下数据:

_id:1, country:india,  quantity:12,  name:xyz
_id:2, country:USA,    quantity:5,   name:abc
_id:3, country:USA,    quantity:6,   name:xyz
_id:4, country:india,  quantity:8,   name:def
_id:5, country:USA,    quantity:10,  name:jkl
_id:6, country:india,  quantity:12,  name:jkl
Run Code Online (Sandbox Code Playgroud)

答案应该是

country:india max-quantity:12
name xyz
name jkl 

country:USA max-quantity:10
name jkl
Run Code Online (Sandbox Code Playgroud)

我已经尝试了几个查询,但是我只能获得没有名称的最大值,或者我可以分组,但它显示了所有的值.

db.coll.aggregate([{
    $group:{
        _id:"$country",
        "maxQuantity":{$max:"$quantity"}
    }
}])
Run Code Online (Sandbox Code Playgroud)

例如,上面将给出每个国家的最大数量但是如何与其他领域结合使得它显示最大数量的所有文件.

Bla*_*ven 12

如果你想保留文档信息,那么你基本上需要把$push它放到一个数组中.但是当然,然后拥有您的$max值,您需要过滤数组的内容以仅匹配匹配的元素:

db.coll.aggregate([
    { "$group":{ 
        "_id": "$country",
        "maxQuantity": { "$max": "$quantity" },
        "docs": { "$push": {
            "_id": "$_id",
            "name": "$name",
            "quantity": "$quantity"
        }}
    }},
    { "$project": {
        "maxQuantity": 1,
        "docs": {
            "$setDifference": [
               { "$map": {
                   "input": "$docs",
                   "as": "doc",
                   "in": {
                       "$cond": [ 
                           { "$eq": [ "$maxQuantity", "$$doc.quantity" ] },
                           "$$doc",
                           false
                       ]
                   }
               }},
               [false]
            ]
        }
    }}
])
Run Code Online (Sandbox Code Playgroud)

因此,您将所有内容存储在一个数组中,然后测试每个数组成员,以查看它的值是否与记录为最大值的值匹配,丢弃任何不成功的值.

我将_id值保留在数组文档中,因为这是使它们"唯一"的原因,并且$setDifference在过滤掉值时不会受到不利影响.但是,如果"名称"始终是唯一的,那么它将不是必需的.

你也可以只返回你想要的任何字段$map,但我只是返回整个文档.

请记住,这具有不超过16MB的BSON大小限制的限制,因此对于小数据样本是可以的,但是产生可能大的列表的任何内容(因为您不能预先过滤阵列内容)将更好地处理单独查询以查找"max"值,另一个查询以获取匹配文档.

  • 不知道为什么这是被接受的答案而不是另一个 - 正确的答案只是 $sort 和 $group 采取 $first 。这是不必要的复杂,而且根本无法扩展。 (2认同)