我不喜歡你的建議的輸出格式。你基本上要求的 正在把你的「數據」,並將其轉化爲所產生結果的「關鍵」。對我來說,這是清潔面向對象設計的對立面,因爲每個「對象」都是完全不同的,你基本上需要循環鍵來確定它是什麼類型的東西。
更好的方法是,保持鍵,因爲它們是,捲起的「客戶端」的組合與$group
和「類型」,然後$group
再次$push
每「類型」的數據轉換成用於每一個陣列分組「客戶端」:
db.getCollection('issues').aggregate([
{ "$group": {
"_id": {
"client": "$client",
"type": "$type"
},
"totalTime": { "$sum": "$time" }
}},
{ "$group": {
"_id": "$_id.client",
"data": {
"$push": {
"type": "$_id.type",
"totalTime": "$totalTime"
}
}
}}
])
這給了你這樣一個結果:
{
"_id" : "client1",
"data" : [
{
"type" : "Test",
"totalTime" : 5
},
{
"type" : "Defect",
"totalTime" : 5
}
]
}
{
"_id" : "client2",
"data" : [
{
"type" : "Defect",
"totalTime" : 3
},
{
"type" : "Management",
"totalTime" : 3
}
]
}
{
"_id" : "client3",
"data" : [
{
"type" : "Test",
"totalTime" : 4
}
]
}
這對我來說是每個「客戶」結果的完全自然的和結構化的形式作爲文件和自然可迭代列表,因爲它的內容。
如果你真的堅持使用命名鍵的單一對象輸出格式,那麼這個源代碼很容易轉換。而在我看來簡單的代碼再次演示瞭如何更好的一個結果是:
var output = {};
db.getCollection('issues').aggregate([
{ "$group": {
"_id": {
"client": "$client",
"type": "$type"
},
"totalTime": { "$sum": "$time" }
}},
{ "$group": {
"_id": "$_id.client",
"data": {
"$push": {
"type": "$_id.type",
"totalTime": "$totalTime"
}
}
}}
]).forEach(function(doc) {
output[doc._id] = {};
doc.data.forEach(function(data) {
output[doc._id][data.type] = data.totalTime;
});
});
printjson(output);
然後你得到你的對象,只要你喜歡:
{
"client1" : {
"Test" : 5,
"Defect" : 5
},
"client2" : {
"Defect" : 3,
"Management" : 3
},
"client3" : {
"Test" : 4
}
}
但如果你是在服務器上真正堅持搗弄所有的工作,甚至沒有過載的結果的重塑,那麼你可以隨時解僱這是MapReduce的:
db.getCollection('issues').mapReduce(
function() {
var output = { },
data = {};
data[this.type] = this.time;
output[this.client] = data;
emit(null,output)
},
function(key,values) {
var result = {};
values.forEach(function(value) {
Object.keys(value).forEach(function(key) {
if (!result.hasOwnProperty(key))
result[key] = {};
Object.keys(value[key]).forEach(function(dkey) {
if (!result[key].hasOwnProperty(dkey))
result[key][dkey] = 0;
result[key][dkey] += value[key][dkey];
})
})
});
return result;
},
{ "out": { "inline": 1 } }
)
具有相同類型的輸出:
{
"_id" : null,
"value" : {
"client1" : {
"Defect" : 5,
"Test" : 5
},
"client2" : {
"Management" : 3,
"Defect" : 3
},
"client3" : {
"Test" : 4
}
}
}
不過既然是MapReduce的,該interpeted的JavaScript會比聚合管道的本地代碼運行 慢得多,當然絕不會擴展到生產超過16MB BSON限制的文檔的結果,因爲所有的結果都被嵌入到一個文檔中。
另外,只需查看遍歷對象鍵,檢查鍵,創建和添加的複雜性。這實際上只是一團糟,並且是任何進一步的代碼與這樣的結構一起工作的指示器。
因此,爲了我的錢,遠離將完美結構良好的數據轉換成實際「值」被表示爲「鍵」的東西。從簡潔的設計角度來看,它確實沒有任何意義,也沒有使用遍歷對象的鍵來取代自然的「數組」列表。
你的值是字符串不是數字。如果您有兩個具有相同鍵/值對的文檔,例如'{client:'client1',type:'Defect',time:'5'}'?你想在這裏做什麼? – styvane
您運行的是哪個版本的MongoDB? – Saleem
請發佈您的聚合代碼,以便我們可以幫助您基於迄今爲止的內容。 – metame