2017-08-29 27 views
1

我有一個MongoDB的集合,它看起來像這樣:計數和組上的按鍵的出現和他們的價值觀

[{ 
     "installer": "anthony", 
     "tester": "bob" 
    }, { 
     "installer": "chris", 
     "tester": "anthony" 
    }, { 
     "installer": "bob", 
     "tester": "dave" 
    }, { 
     "installer": "anthony", 
     "tester": "chris" 
    }, { 
     "installer": "chris", 
     "tester": "dave" 
    } 
] 

我想使用aggregate,所以我可以指望每個名字出現的次數每一個區域內和檢索結果如下:

[{ 
     "name": "anthony", 
     "installer": 2, 
     "tester": 1 
    }, { 
     "name": "bob", 
     "installer": 1, 
     "tester": 1 
    }, { 
     "name": "chris", 
     "installer": 2, 
     "tester": 1 
    }, { 
     "name": "dave", 
     "installer": 0, 
     "tester": 2 
    } 
] 

這是我迄今完成查詢,問題是,它僅返回nameinstaller計數沒有tester計數。我可以運行這個查詢兩次(一個用於installer和一個用於tester),但我想找到一種方法來同時返回兩個計數。

db.data.aggregate([ 
    { 
     "$group": { 
      "_id": "$installer", 
      "installer": { "$sum": 1 } 
     }, 
     "$project": { 
      "name": "$_id", 
      "installer": 1, 
      "_id": 0 
     } 
    } 
]) 

怎樣更改我的查詢需要,所以我可以同時獲得每個人的installertester計數?

+0

這應該對你有幫助:https://stackoverflow.com/questions/18501064/mongodb-aggregation-counting-distinct-fields –

回答

2

你基本上要$cond選擇是否通過10$sum累加器在$group管道,和一個初始值「陣列」使用$unwind創造每個人的文件的副本兩個領域。

db.data.aggregate([ 
    { "$addFields": { 
    "val": ["$installer","$tester"]  
    }}, 
    { "$unwind": "$val" }, 
    { "$group": { 
    "_id": { "_id": "$_id", "val": "$val" }, 
    "installer": { 
     "$max": { 
     "$cond": [ 
      { "$eq": ["$installer","$val"] }, 
      1, 
      0 
     ] 
     }  
    }, 
    "tester": { 
     "$max": { 
     "$cond": [ 
      { "$eq": ["$tester","$val"] }, 
      1, 
      0 
     ] 
     }  
    } 
    }}, 
    { "$group": { 
    "_id": "$_id.val", 
    "installer": { "$sum": "$installer" }, 
    "tester": { "$sum": "$tester" } 
    }} 
]) 

爲了應對該商品的特定文件可以有相同的「安裝程序」,我們其實應該在「文件」每發射「VAL」作爲第一步聚合「測試」值的情況。使用$max累加器中的$cond使此情況成爲「單個」文檔而不是「兩個」,對於每個數組條目都是一個。

當然,另一種情況是簡單地通過應用$setUnion對初步名單,以避免在這種情況下重複返回值的「設置」:

db.data.aggregate([ 
    { "$addFields": { 
    "val": { "$setUnion": [["$installer","$tester"]] } 
    }}, 
    { "$unwind": "$val" }, 
    { "$group": { 
    "_id": "$val", 
    "installer": { 
     "$sum": { 
     "$cond": [ 
      { "$eq": ["$installer","$val"] }, 
      1, 
      0 
     ] 
     }  
    }, 
    "tester": { 
     "$sum": { 
     "$cond": [ 
      { "$eq": ["$tester","$val"] }, 
      1, 
      0 
     ] 
     }  
    } 
    }} 
]) 

我添加了一個文件到您的源作爲:

{ "installer": "jack", "tester": "jack" } 

爲了說明結果。

至於$cond,它是一個「三元」或if..then..else條件,這裏的參數是「第一」 if一個條件評價爲布爾型,then作爲值返回時trueelse作爲值時返回條件是false

可以交替這樣寫:

"$cond": { 
    "if": { "$eq": ["$installer","$val"] }, 
    "then": 1, 
    "else": 0 
} 

但原來的「陣」的語法更簡單一點寫簡單表達式。大多數人仍然會認識到它的「三元」,但如果你認爲它使代碼更清晰,那麼你可以使用「命名鍵」形式。

當然結果是1當該字段是存在於文檔中僅返回,使正確的計數:

/* 1 */ 
{ 
    "_id" : "jack", 
    "installer" : 1.0, 
    "tester" : 1.0 
} 

/* 2 */ 
{ 
    "_id" : "dave", 
    "installer" : 0.0, 
    "tester" : 2.0 
} 

/* 3 */ 
{ 
    "_id" : "bob", 
    "installer" : 1.0, 
    "tester" : 1.0 
} 

/* 4 */ 
{ 
    "_id" : "chris", 
    "installer" : 2.0, 
    "tester" : 1.0 
} 

/* 5 */ 
{ 
    "_id" : "anthony", 
    "installer" : 2.0, 
    "tester" : 1.0 
} 

添加初始「陣列」的文檔可以交替使用$project來完成如果你的MongoDB版本不支持$addFields。唯一不同的是「明確的」,包括那些以後需要其他字段:

{ "$project": { 
    "tester": 1, 
    "installer": 1, 
    "val": { "$setUnion": [["$installer","$tester"]] } 
}} 

如果你的MongoDB是實際上仍然比MongoDB的3.2,它允許這是一個「陣列」的符號,那麼你可以使用$map代替舊的從MongoDB的2.6和向上:

{ "$project": { 
    "tester": 1, 
    "installer": 1, 
    "val": { 
    "$setUnion": [ 
     { "$map": { 
     "input": ["A","B"], 
     "as": "a", 
     "in": { 
      "$cond": [{ "$eq": ["$$a", "A"] }, "$installer", "$tester"] 
     } 
     } 
    ] 
    } 
}} 

再次使用$cond以交替地選擇呈現作爲數組元素,其值。

此外,你真的應該避免做一些事情,比如在語句結尾添加$project。你當然可以這樣做,但這確實意味着前一個管道階段的所有結果都將「再次運行」,以便進行其他更改。對於將"_id"更改爲"name"這樣微不足道的事情,通常只需接受將「分組鍵」稱爲_id並將其留在那裏的做法通常會更好。

作爲$group結果,它實際上是「唯一標識符」爲其_id是通用術語。

+0

感謝您的回覆和詳細的解釋 – dat3450

+0

看來查詢翻倍的實際數字,所以而不是安裝程序「:2'和'」tester「:1'代表'anthony',它分別返回'4'和'2'。 – dat3450

+0

當'installer'和'tester'是同一個人,例如''安裝程序「:」bob「,」tester「:bob' – dat3450