从数组中过滤max并展平文档

时间:2014-05-21 22:29:29

标签: c# mongodb mapreduce aggregation-framework

我是mongo的新手,我的文档看起来像波纹管

{
  Abc : [
   { _id : 1 , val : "somevalue" },
   { _id : 2 , val : "new value" },
   { _id : 3 , val : "new new value" }
  ],
  Xyz : [
    { _id : 1 , val : 3456},
    { _id : 2 , val : 7689 },
    { _id : 3 , val : 21342}
  ],
  Ghi : [
    { _id : 1 , val : "somevalue" },
    { _id : 2 , val : "new value" },
    { _id : 3 , val : "new new value" }
  ],
}

每个字段值应按max _id过滤, 即Abc:“新的新价值”

结果输出应该看起来像

{
  _id : 1
  Abc : "new new value",
  Xyz : 21342,
  Ghi : "new new value"
}

注意:db

中的字段可能有所不同或可能不存在

1 个答案:

答案 0 :(得分:0)

如果您正在使用.find()查看标准投影,那么“排序”或“展平”数组成员的选项确实不多,但如果元素已经是最快的选项按顺序:

db.test.find({},{ 
    "Abc": { "$slice": -1 },
    "Ghi": { "$slice": -1 },
    "Xyz": { "$slice": -1 }
})

用它的输出:

{
    "_id" : ObjectId("537d876dbeeccb8f75e1ef9a"),
    "Abc" : [{ "_id" : 3, "val" : "new new value" }],
    "Xyz" : [{ "_id" : 3, "val" : 21342 }],
    "Ghi" : [{ "_id" : 3, "val" : "new new value" }]
}
{
    "_id" : ObjectId("537d87fe348f6339113e85ae"),
    "Abc" : [{ "_id" : 3, "val" : "new new value" }],
    "Ghi" : [{ "_id" : 3, "val" : "new new value" }]
}

如果您准备提名所有可能的字段,您可以使用聚合框架执行类似的操作:

db.test.aggregate([
    { "$project": {
        "Abc": { "$ifNull": [ "$Abc", [ false ] ] },
        "Ghi": { "$ifNull": [ "$Ghi", [ false ] ] },
        "Xyz": { "$ifNull": [ "$Xyz", [ false ] ] }
    }},
    { "$unwind": "$Abc" },
    { "$unwind": "$Ghi" },
    { "$unwind": "$Xyz" },
    { "$sort": { "Abc._id": -1, "Ghi._id": -1, "Xyz": -1 } },
    { "$group": {
        "_id": "$_id",
        "Abc": { "$first": "$Abc.val" },
        "Ghi": { "$first": "$Ghi.val" },
        "Xyz": { "$first": "$Xyz.val" }
    }}
])

如果使用$ifNull运算符不存在该字段以阻止后面的$unwind语句爆炸,那么基本上会在其中放置[ false ]数组。里程数可能会有所不同,这是否适合您。它是输出:

{
    "_id" : ObjectId("537d876dbeeccb8f75e1ef9a"),
    "Abc" : "new new value",
    "Ghi" : "new new value",
    "Xyz" : 21342
}
{
    "_id" : ObjectId("537d87fe348f6339113e85ae"),
    "Abc" : "new new value",
    "Ghi" : "new new value",
    "Xyz" : null
}

或者你可以使用mapReduce做一些更复杂的事情,即使没有实际的减少:

db.test.mapReduce(
    function () {

      for ( var k in this ) {
        if ( k === '_id' )
          continue;

        this[k].sort(function(a, b) {
          if ( a._id < b._id ) {
            return -1;
          } else if ( a._id > b._id ) {
            return 1;
          }
          return 0;
        });

        this[k] = this[k].slice(-1)[0].val;

      }

      var id = this._id;
      delete this["_id"];

      emit( id, this );

    },
    function(){},
    {
        "out": { "inline": 1 }
    }
)

哪个有可怕的mapReduce输出,但至少你可以灵活使用文档中的“键”:

    "results" : [
        {
            "_id" : ObjectId("537d876dbeeccb8f75e1ef9a"),
            "value" : {
                "Abc" : "new new value",
                "Xyz" : 21342,
                "Ghi" : "new new value"
            }
        },
        {
            "_id" : ObjectId("537d87fe348f6339113e85ae"),
            "value" : {
                "Abc" : "new new value",
                "Ghi" : "new new value"
            }
        }
    ]

这是一些考虑各自优势和劣势的方法,但却是一种完成工作的方法。