2014-07-09 28 views
1

所以我有一個收集如何聚集數據以嵌套陣列輸出

在以下數據{ 「UID」:567, 「AN0」:100, 「AN1」:150,曆元:1401399336437}
「UID」:123,「AN0」:200,「AN1」:250,epoch:1401399336438}
{「UID」:567,「AN0」:300,「AN1」:350,epoch:1401399336439}
...

對於UID:567 & & AN0我想得到的輸出類似於:

{鍵: 「AN0」
值:[
    [1401399336437,100]
    [1401399336439,300]
]
}

我已經或多或少的使用GROUP,如下所示:

db.Datasets.group({ 
     cond: {UID: "567", AN0:{$exists:true}, epoch:{$exists:true}}, 
     initial: {key:"", values: []}, 
     reduce: function(obj, prev){ 
     var temp =[]; 
     temp.push(obj.epoch); 
     temp.push(obj.AN0); 
     prev.values.push(temp); 
     }, 
     finalize: function(result){ 
      result.key = "AN0"; 
     } 
}) 

但是這種方法給我提供了很多問題時,與reduce和finalize函數共享範圍。

所以我想這樣做與聚合管道

我試圖

db.Datasets.aggregate([ 
    {$match:{ UID: "567" , AN0: {$exists:true} }}, 
    {$group : { _id: "$UID", value1: { $push: "$epoch"}, value2: { $push: "$AN0"} }}, 
]) 

我得到

{值1:1401399336437,1401399336439],
    value2:[100,300]

如何改變這種狀況得到

值:
    [1401399336437,100]
    [1401399336439,300]
]

謝謝!

回答

0

對我來說,我會做一些不同的聚合,然後後處理結果。

var res = db.collection.aggregate([ 
    { "$group": { 
     "_id": "$UID", 
     "value": { 
      "$push": { 
       "a": "$epoch", "b": "$AN0" 
      } 
     } 
    }} 
]).toArray() 

在這一階段的結果是這樣的:

[ 
    { "_id" : 123, "value" : [ { "a" : 1401399336438, "b" : 200 } ] }, 
    { "_id" : 567, "value" : [ { "a" : 1401399336437, "b" : 100 }, { a" : 1401399336439, "b" : 300 } ]} 
] 

現在只是變換:

var res = res.map(function(doc) { 
    doc.value = doc.value.map(function(x){ 
     return [x.a,x.b] 
    }); 
    return doc; 
}) 

但是,如果你真的有決心做到這一點,有MongoDB的2.6可用,有總是這樣:

db.collection.aggregate([ 
    { "$group": { 
     "_id": "$UID", 
     "val": { 
      "$push": { 
       "a": "$epoch", "b": "$AN0" 
      } 
     } 
    }}, 
    { "$project": { 
     "value": { 
      "$map": { 
       "input": "$val", 
       "as": "el", 
       "in": { 
        "$map": { 
         "input": { "$literal": ["A","B"] }, 
         "as": "type", 
         "in": { 
          "$cond": [ 
           { "$eq": [ "$$type", "A" ] }, 
           "$$el.a", 
           "$$el.b" 
          ] 
         } 
        } 
       } 
      } 
     } 
    }} 
]) 

這裏的訣竅在$map聲明中。基本上,這將返回一個數組,爲源輸入指定爲文字["A","B"]。因此,只要「外部」$ map處理從$push創建的數組中的每個元素,「內部」$ map操作就會處理每個「A」或「B」並測試該值。

$cond操作中,如果當前值爲「A」,則返回外部數組元素的已存變量,因爲它是「a」鍵值,否則返回「b」鍵值。簡而言之,將「外層」中的每個元素替換爲「內層」的替換形式。而不是帶有鍵的文檔,現在在數組中有數組。

在這兩種情況下的輸出是你想要的:

[ 
    { 
      "_id" : 123, 
      "value" : [ 
        [ 
          1401399336438, 
          200 
        ] 
      ] 
    }, 
    { 
      "_id" : 567, 
      "value" : [ 
        [ 
          1401399336437, 
          100 
        ], 
        [ 
          1401399336439, 
          300 
        ] 
      ] 
    } 
] 
+0

您可以通過第二個解決方案顯得相當有經驗的判斷。這個解決方案比mapReduce實現更快嗎?我想要這種格式的數據的原因是NVD3圖形庫避免重新處理客戶端中的數據。 – opcode

+0

@opcode快得多。 MapReduce和其他類似組的操作依賴於JavaScript處理,因爲這需要通過解釋器來運行,所以它比用本地代碼實現的聚合管道要慢得多。 –