2015-11-30 18 views
8

Ben her departmanHer grup için ilgili belgelerin dizisi ile bir alanın maksimum değeri nasıl alınır?

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

Ben en yüksek maaş alabilir tarafından

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

Ben en yüksek maaş ile sonuçlar istedikleri gibi bir koleksiyona sahip. Ama karşılık gelen çalışan isimlerini alamadım.

db.HR.aggregate([ 

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

Birisi bana yardımcı olabilir mi?

+0

harika bir soru, size denenmiş ve bir hata var ne ekleyebilir miyim? – inspired

+0

SQL'de kendini birleştirme ile çözebilirim. Ama Mongo ile bir yol bulamıyorum – dapangmao

cevap

7

Sen $unwind sonra belgenizi $sort ve $group aşamasında $first operatörünü kullanmak gerekir. Ayrıca artan düzende belgelerinizi sıralamak gerekir ki bu durumda $last operatörünü kullanabilirsiniz üretir

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 } 

maksimum maaş ve çalışanların listesini döndürmek için Her bölüm için her grup için maksimum "Maaş" değerini döndürmek için grup sahnesinde $max'u kullanmanız gerekir, daha sonra "Ad" listesini döndürmek için $push akümülatör operatörünü kullanın Her grup için tüm çalışanlar için "ve" Maaş ". Buradan, maksimum maaşla birlikte isimlerin listesini döndürmek için $project sahnesinde $map operatörünü kullanmanız gerekir. Tabii ki $cond, her çalışan maaşını maksimum değere karşılaştırmak için kullanılır. $setDifference, tüm false filtrelerini işten çıkarır ve filtrelenen veriler "benzersiz" olduğu sürece iyidir. Bu durumda, "iyi olmalı", ancak herhangi iki sonuç aynı "isim" içeriyorsa, o zaman iki olmak için bir tane düşünerek sonuçları çarpıtır. Ama bunun yerine $max ait

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

Onun değil en sezgisel şey $sort ve $first kullanarak olmalıdır: verir

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

Alternatif

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

, bu yapılabilir olduğunu düşünüyorum $$ROOT operatörünü kullanma (adil uyarı: Bunu gerçekten denemedim) -

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

Başka bir olası çözüm:

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

Bu çözüm $project aşamasında iki alanı karşılaştırmak için $eq operatör yararlanır.

Test durumda:

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

Sonuç:

{ "_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 } 
İlgili konular