操纵MongoDB结果以动态生成字段名称

时间:2014-10-27 23:09:12

标签: javascript mongodb mapreduce mongodb-query aggregation-framework

我正在尝试重构Mongo查询的结果,以使用属性调用'field'中的值作为结果中的键。

我有一个查询返回我的结果:

[
{
    "_id" : ObjectId("544ecbf11972fd515fd6306c"),
    "field" : "fieldOne",
    "value" : "fieldOneValue"
},
 "_id" : ObjectId("544ecbf11972fd515fd6307c"),
    "field" : "fieldTwo",
    "value" : "fieldTwoValue",
},
{
 "_id" : ObjectId("544ecbf11972fd515fd6308c"),
    "field" : "fieldThree",
    "value" : "fieldThreeValue"
}
]

有没有办法得到这样的结果:

{
   fieldOne:fieldOneValue,
   fieldTwo:fieldTwoValue,
   fieldThree:fieldThreeValue
}

2 个答案:

答案 0 :(得分:0)

可以使用mapReduce执行此操作,因为基本上您需要JavaScript处理来生成动态密钥。

映射非常简单:

var mapper = function () {
  var obj = {};

  obj[this.field] = this.value;
  emit(1,obj);
};

并且减速器只是将所有发出的元素与相同的"键"值:

var reducer = function (key,values) {

  var reduced = {};

  values.forEach(function(value) {
    Object.keys( value ).forEach(function(key) {
      reduced[key] = value[key];
    });
  });

  return reduced;

};

简单地打电话并获得结果,尽管是在一个非常" mapReduce"因为这就是输出总是如此:

db.threedocs.mapReduce(mapper,reducer,{ out: { inline: 1 } })
{
    "results" : [
            {
                    "_id" : 1,
                    "value" : {
                            "fieldOne" : "fieldOneValue",
                            "fieldTwo" : "fieldTwoValue",
                            "fieldThree" : "fieldThreeValue"
                    }
            }
    ],
    "timeMillis" : 6,
    "counts" : {
            "input" : 3,
            "emit" : 3,
            "reduce" : 1,
            "output" : 1
    },
    "ok" : 1
}

聚合框架可以更接近更好的输出,但只能处理静态数据而不能动态地#34;分配未知的密钥名称。但如果你知道会发生什么,你可以这样做:

db.threedocs.aggregate([
    { "$group": {
        "_id": null,
        "fieldOne": {
            "$max": {
               "$cond": [
                   { "$eq": [ "$field", "fieldOne" ] },
                   "$value",
                   0
               ]
            }
        },
        "fieldTwo": {
            "$max": {
               "$cond": [
                   { "$eq": [ "$field", "fieldTwo" ] },
                   "$value",
                   0
               ]
            }
        },
        "fieldThree": {
            "$max": {
               "$cond": [
                   { "$eq": [ "$field", "fieldThree" ] },
                   "$value",
                   0
               ]
            }
        }
    }},
    { "$project": {
        "_id": 0,
        "fieldOne": 1,
        "fieldTwo": 1,
        "fieldThree": 1
    }}
])

输出更好:

{
    "fieldOne" : "fieldOneValue",
    "fieldTwo" : "fieldTwoValue",
    "fieldThree" : "fieldThreeValue"
}

在任何一种情况下,操作都相当简单,并没有真正考虑到"字段"的多个值的存在。或者如何处理它们。在现实世界聚合术语中,最好坚持使用所呈现的数据模式,而不是试图表示数据点" as" keys"因为这基本上要求。但是不可能从这样的样本中确定真正的用途是什么。

答案 1 :(得分:0)

使用 MongoDB 4.4(没有检查以前的版本):

db.coll.aggregate($project: {
  $arrayToObject:
      {$map:
        {
          input: "$arrayToParse",
          as: "this",
          in: {
            "k":"$$this.field",
            "v":"$$this.value"
          }
        }
      }
    }
)