2015-11-30 9 views
8

私は対応する文書の配列を持つ各グループのフィールドの最大値を取得するにはどうすればよいですか?

{ 
    "_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" } 
     } 
    } 
]) 

誰か助けてもらえますか?

+0

偉大な質問、あなたがしようとしたエラーを持っているものを追加することはできますか? – inspired

+0

私は自己結合でSQLでそれを解決できました。しかし、私はモンゴで道を見つけることができません – dapangmao

答えて

7

$unwindの後に文書を$sortに、$groupステージで$firstオペレータを使用する必要があります。また、あなたが昇順でドキュメントをソートする必要があります。その場合に$last演算子を使用することができます生成

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

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

が最大の給与と従業員のリストを返すには部門ごとにグループステージで$maxを使用して各グループの最大給与額を返す必要があります。$pushアキュムレータ演算子を使用して、「名前「給与」を各グループの全従業員に適用します。そこから$projectステージで$mapオペレーターを使用して、最高給与と並んで名前のリストを返す必要があります。もちろん$condは、各従業員の給与を最大値と比較するために使用されます。 $setDifference彼の作品はすべてfalseで除外されており、フィルタリングされるデータが「ユニーク」である限り問題はありません。この場合、「うまくいく」必要がありますが、2つの結果に同じ「名前」が含まれている場合は、2つを1とみなして結果を歪ませます。が、その代わりに$max

{ "_id" : "Sales", "maxSalary" : 80000, "persons" : [ "Henry" ] } 
{ "_id" : "IT", "maxSalary" : 90000, "persons" : [ "Sam" ] } 
3

そのない最も直感的な事はあなたが$sort$first使用する必要があります:得

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] 
      ] 
     } 
    }} 
]) 

また

{ "$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" 
     } 
    } 
} 
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 
    }} 
]) 

この溶液を$projectステージ内の2つのフィールドを比較する$eqオペレータを利用します。

テストケース:

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 } 
関連する問題