【问题标题】:Filtering max from array and flattening document从数组中过滤最大值并展平文档
【发布时间】:2014-05-21 22:29:28
【问题描述】:

我是 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 中

【问题讨论】:

  • “字段可能不同或可能不存在”是指字段 Abc/Xyc/Ghi,还是说它们可能是空数组?
  • 嗨耀星,是的,我的意思是 ABC/Xyz/Ghi

标签: c# mongodb mapreduce aggregation-framework


【解决方案1】:

如果您使用.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"
            }
        }
    ]

因此,这是考虑到他们个人优势和劣势的一些方法,但也是完成工作的一种方式。

【讨论】:

  • 非常感谢 :) 我真的很喜欢 map reduce 方法,我只是想知道是否有任何方法可以在实际文档中使用这些属性“abc”、“xyz”而不是值。再次非常感谢您
猜你喜欢
  • 1970-01-01
  • 2021-07-02
  • 2017-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-26
  • 1970-01-01
相关资源
最近更新 更多