动态汇总所有文档密钥

时间:2018-06-06 10:58:05

标签: mongodb aggregation-framework

我的文档结构如下:

{"x":1, "y":1}

其中密钥未知且动态。我想要一个聚合所有字段的结果。 示例: 如果我的收藏包括:

{"x":1, "y":10}
{"x":1, "y":20}
{"x":2 , "z":13}

我希望结果是

{"sum":{"x":4, "y":30,"z":13}

这怎么可能?

1 个答案:

答案 0 :(得分:2)

使用MongoDB 3.6,您可以使用$objectToArray$arrayToObject将对象拆分并累积:

db.collection.aggregate([
 { "$project": {
    "data": {
      "$filter": {
        "input": { "$objectToArray": "$$ROOT" },
        "cond": { "$ne": [ "$$this.k", "_id" ] }
      }
    }
 }},
 { "$unwind": "$data" },
 { "$group": {
   "_id": "$data.k",
   "v": { "$sum": "$data.v" }
 }},
 { "$sort": { "_id": 1 } },
 { "$group": {
   "_id": null,
   "data": { "$push": { "k": "$_id", "v": "$v" } }
 }},
 { "$replaceRoot": { 
   "newRoot": { "$arrayToObject": "$data" }
 }}
])

返回:

{ "x" : 4, "y" : 30, "z" : 13 }

如果您没有支持这些运营商的MongoDB,基本上与mapReduce()相同:

db.collection.mapReduce(
  function() {
    var doc = this;
    delete doc._id;
    emit(null, doc);
  },
  function(key,values) {
    var output = {};
    values.forEach(value =>
      Object.keys(value).forEach(k => {
        if (!output.hasOwnProperty(k))
          output[k] = 0;
        output[k] = output[k] + value[k];
      })
    );
    return output;
  },
  { "out": { "inline": 1 } }
)

略有不同,mapReduce样式输出:

    {
            "_id" : null,
            "value" : {
                    "x" : 4,
                    "y" : 30,
                    "z" : 13
            }
    }