【问题标题】:How to aggregate data to nested array output如何将数据聚合到嵌套数组输出
【发布时间】:2014-08-31 03:22:12
【问题描述】:

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

{ "UID" : 567, "AN0" : 100, "AN1" : 150, epoch:1401399336437 }
{ “UID”:123,“AN0”:200,“AN1”:250,纪元:1401399336438 }
{ “UID”:567,“AN0”:300,“AN1”:350,纪元: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"} }},
] )

我明白了

{ value1:[ 1401399336437, 1401399336439 ],
值2:[100, 300]

如何改变它来获得

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

谢谢!

【问题讨论】:

    标签: node.js mongodb aggregation-framework


    【解决方案1】:

    对我来说,我会稍微不同地进行聚合,然后对结果进行后期处理。

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

    【讨论】:

    • 从第二种解决方案来看,您似乎很有经验。这个解决方案比 mapReduce 实现更快吗?我想要这种格式的数据的原因是为了NVD3图形库避免在客户端重新处理数据。
    • @opcode 快得多。 MapReduce 和其他操作如 group 依赖于 JavaScript 处理,因为这需要通过解释器运行,它比在本机代码中实现的聚合管道慢得多。
    猜你喜欢
    • 2019-11-07
    • 2019-10-06
    • 2017-07-26
    • 1970-01-01
    • 2021-11-05
    • 1970-01-01
    • 2020-05-09
    • 2020-11-09
    • 1970-01-01
    相关资源
    最近更新 更多