如何使用相应文档的数组获取每个组的字段的最大值?

时间:2015-11-30 21:02:11

标签: mongodb mongodb-query aggregation-framework

我有一个像

这样的集合
{
    "_id" : ObjectId("5738cb363bb56eb8f76c2ba8"),
    "records" : [
        {
            "Name" : "Joe",
            "Salary" : 70000,
            "Department" : "IT"
        }
    ]
},
{
    "_id" : ObjectId("5738cb363bb56eb8f76c2ba9"),
    "records" : [
        {
            "Name" : "Henry",
            "Salary" : 80000,
            "Department" : "Sales"
        },
        {
            "Name" : "Jake",
            "Salary" : 40000,
            "Department" : "Sales"
        }
    ]
},
{
    "_id" : ObjectId("5738cb363bb56eb8f76c2baa"),
    "records" : [
        {
            "Name" : "Sam",
            "Salary" : 90000,
            "Department" : "IT"
        },
        {
            "Name" : "Tom",
            "Salary" : 50000,
            "Department" : "Sales"
        }
    ]
}

我想得到每个部门薪水最高的结果

{"Name": "Sam", "Salary": 90000, "Department": "IT"}
{"Name": "Henry", "Salary": 80000, "Department": "Sales"}

我可以获得最高薪水。但我无法获得相应的员工姓名。

db.HR.aggregate([

    { "$unwind": "$records" },
    { "$group": 
        {
            "_id": "$records.Department",
            "max_salary": { "$max": "$records.Salary" }
        }
    }   
])

有人能帮助我吗?

3 个答案:

答案 0 :(得分:7)

您需要$sort之后$unwind您的文档,并在$first阶段使用$group运算符。您也可以使用$last运算符,在这种情况下,您需要按升序对文档进行排序

sizeof vals

产生:

db.HR.aggregate([
    { '$unwind': '$records' }, 
    { '$sort': { 'records.Salary': -1 } }, 
    { '$group': { 
        '_id': '$records.Department', 
        'Name': { '$first': '$records.Name' } , 
        'Salary': { '$first': '$records.Salary' }
    }}
])

要返回每个部门的最高工资和员工列表,您需要在小组阶段使用$max来返回最高"薪水"对于每个组,然后使用$push累加器运算符返回"名称"和"薪水"适用于每个组的所有员工。从那里,您需要使用$map阶段中的$project运算符返回名称列表以及最高薪水。当然,此处的$cond用于将每个员工薪水与最大值进行比较。 $setDifference完成了他的工作,即过滤掉所有{ "_id" : "Sales", "Name" : "Henry", "Salary" : 80000 } { "_id" : "IT", "Name" : "Sam", "Salary" : 90000 } ,只要被过滤的数据是"唯一的"就可以了。在这种情况下,它应该""没问题,但如果任何两个结果包含相同的名称"然后通过将两者视为一个来扭曲结果。

false

产生:

db.HR.aggregate([
    { '$unwind': '$records' },
    { '$group': {
        '_id': '$records.Department', 
        'maxSalary': { '$max': '$records.Salary' }, 
        'persons': { 
            '$push': {
                'Name': '$records.Name', 
                'Salary': '$records.Salary' 
            }
        }
    }}, 
    { '$project': { 
        'maxSalary': 1, 
        'persons': { 
            '$setDifference': [
                { '$map': {
                    'input': '$persons', 
                    'as': 'person', 
                    'in': {
                        '$cond': [
                            { '$eq': [ '$$person.Salary', '$maxSalary' ] }, 
                            '$$person.Name', 
                            false
                        ]
                    }
                }}, 
                [false]
            ]
        }
    }}
])

答案 1 :(得分:3)

这不是最直观的事情,但您应该使用$max$sort代替$first

{ "$unwind": "$records" },
{ "$sort": { "$records.Salary": -1},
{ "$group" : 
    {
        "_id": "$records.Department",
        "max_salary": { "$first": "$records.Salary" },
        "name": {$first: "$records.Name"}
    }
}

或者,我认为使用$$ROOT运算符是可行的(公平警告:我实际上没有尝试过这个) -

{ "$unwind": "$records" },
{ "$group": 
        {
            "_id": "$records.Department",
            "max_salary": { "$max": "$records.Salary" }
            "name" : "$$ROOT.records.Name"
        }
    }
}

答案 2 :(得分:1)

另一种可能的解决方案:

db.HR.aggregate([
    {"$unwind": "$records"},
    {"$group":{
        "_id": "$records.Department",
        "arr": {"$push": {"Name":"$records.Name", "Salary":"$records.Salary"}},
        "maxSalary": {"$max":"$records.Salary"}
    }},
    {"$unwind": "$arr"},
    {"$project": {
        "_id":1,
        "arr":1,
        "isMax":{"$eq":["$arr.Salary", "$maxSalary"]}
    }},
    {"$match":{
        "isMax":true
    }}
])

此解决方案利用$eq运算符来比较$project阶段中的两个字段。

测试用例:

db.HR.insert({"records": [{"Name": "Joe", "Salary": 70000, "Department": "IT"}]})
db.HR.insert({"records": [{"Name": "Henry", "Salary": 80000, "Department": "Sales"}, {"Name": "Jake", "Salary": 40000, "Department": "Sales"}, {"Name": "Santa", "Salary": 90000, "Department": "IT"}]})
db.HR.insert({"records": [{"Name": "Sam", "Salary": 90000, "Department": "IT"}, {"Name": "Tom", "Salary": 50000, "Department": "Sales"}]})

结果:

{ "_id" : "Sales", "arr" : { "Name" : "Henry", "Salary" : 80000 }, "isMax" : true }
{ "_id" : "IT", "arr" : { "Name" : "Santa", "Salary" : 90000 }, "isMax" : true }
{ "_id" : "IT", "arr" : { "Name" : "Sam", "Salary" : 90000 }, "isMax" : true }