过滤最大从数组和平坦的文档



我是新手,我的文档看起来像下面

{
  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: " new new value "

结果输出应该看起来像

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

注意:字段可能不同或可能不存在于db

如果您正在查看.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" }
    }}
])

本质上是把一个[ false ]数组在那里,如果该字段不存在,使用 $ifNull 操作符来阻止后来的 $unwind 语句爆发。这是否是您的解决方案,具体情况可能有所不同。输出:

{
    "_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"
            }
        }
    ]

所以这是考虑到他们各自的优点和缺点的几种方法,但也是一种完成工作的方法。

相关内容

  • 没有找到相关文章

最新更新