如何将数据聚合到嵌套数组输出

时间:2014-07-09 22:50:45

标签: node.js mongodb aggregation-framework

所以我在集合中有以下数据

  

{“UID”:567,“AN0”:100,“AN1”:150,纪元:1401399336437}
  {“UID”:123,“AN0”:200,“AN1”:250,纪元:1401399336438}
  {“UID”:567,“AN0”:300,“AN1”:350,纪元:1401399336439}
  ...

对于UID:567&& AN0我想获得类似于的输出:

  

{key:“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"} }},
] )

我得到了

  

{value1:[1401399336437,1401399336439],
  value2:[100,300]

如何更改

  

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

谢谢!

1 个答案:

答案 0 :(得分: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创建的数组的每个元素," inner" $ map操作处理每个" A"或" B"并测试价值。

$cond操作中,如果当前值为" A"然后返回外部数组元素的已保持变量,因为它是" a"键值,否则返回" b"核心价值。简而言之,替换"外部"中的每个元素。与'#34;内部"的替换形式。您现在在数组中拥有数组,而不是带有键的文档。

两种情况下的输出都是你想要的:

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