【问题标题】:Mongo aggregate group by one array elementMongo 按一个数组元素聚合分组
【发布时间】:2014-09-09 16:22:23
【问题描述】:

我有以下文件:

{
  "_id" : ObjectId("540dadfcf3116b60d401c314"),
  "value" : 2,
  "d_c_at" : [
    "2013",
    "201311",
    "2013w46",
    "20131116"
  ]
}

我想按 d_c_at 数组 (20131116) 中的最后一个元素对它们进行分组,该数组将年、月和日存储为解构日期。

这是我目前所拥有的:

db.points.aggregate(
  { $match: { "d_c_at.0": '2014' } },
  { $group: { _id: "$d_c_at.0", value: { $sum: "$value" } } }
)

返回:

{ "_id" : [ ], "value" : 1207 }

我尝试过使用$unwind,但没有成功:

db.points.aggregate(
  { $match: { "d_c_at.0": '2014' } },
  { $unwind: "$d_c_at" },
  { $group: { _id: "$d_c_at", value: { $sum: "$value" } } }
)

看起来几乎不错,但它也可以在其他数组元素上分组:

{ ... }
{ "_id" : "20140519", "value" : 33 }
{ "_id" : "20140707", "value" : 36 }
{ "_id" : "20140330", "value" : 37 }
{ "_id" : "20140709", "value" : -28 }
{ "_id" : "20140620", "value" : 14 }
{ "_id" : "2014w9", "value" : -250 }
{ ... }

预期输出:

{ ... }
{ "_id" : "20140519", "value" : 33 }
{ "_id" : "20140707", "value" : 36 }
{ "_id" : "20140330", "value" : 37 }
{ "_id" : "20140709", "value" : -28 }
{ "_id" : "20140620", "value" : 14 }
{ ... }

【问题讨论】:

  • 为什么要这样存储日期?您可以使用date expression operators 对日期的某些部分进行分组。
  • 为什么不在展开后复制聚合中的匹配项?我不确定预期的输出应该是什么。
  • @wdberkeley 在查询特定年、周、日创建的文档时性能更好
  • @LarryBattle 按问题编辑,预期输出。基本上我想要value 组的总和。
  • @Pierre-LouisGottfrois:为了获得更好的性能,您有 a)多键索引,b)聚合中的额外展开展开阶段(延迟早期匹配),c)大量增加的数据大小,d) 字符串匹配。对不起,但再想想。使用数据表达式运算符到目前为止在所有级别上都是更好的解决方案。

标签: mongodb aggregation-framework


【解决方案1】:

虽然这可以使用聚合来实现,但使用 Map-reduce 可以轻松实现您的预​​期输出: 假设您的 d_c_at 始终有 4 个元素,或者第 4 个元素是您的组 id 标准,如您的示例结构所示。

将key作为第4个元素发出,这样文档就按“d_c_at”的第4个元素分组了。

var map = function(){emit(this.d_c_at[3],{"sum":this.value});} 

完成后,计算总和:

var reduce = function(id,Arr){
var sum = 0;
for(var i=0;i<Arr.length;i++)
    {
        var obj = Arr[i];
        var value = obj.sum;
        sum = sum+value;
    }
    return {"sum":sum};
}

将结果转储到“输出”。

db.test.mapReduce(
                     map,
                     reduce,
                     { out: "output" }
                   )

o/p:

> db.output.find()
{ "_id" : "20131116", "value" : { "sum" : 6 } }
{ "_id" : "20131117", "value" : { "sum" : 6 } }

使用的示例 i/p:

{
  "_id" : 1,
  "value" : 2,
  "d_c_at" : [
    "2013",
    "201311",
    "2013w46",
    "20131116"
  ]
}

{
  "_id" : 2,
  "value" : 4,
  "d_c_at" : [
    "2013",
    "201311",
    "2013w46",
    "20131116"
  ]
}

{
  "_id" : 3,
  "value" : 6,
  "d_c_at" : [
    "2013",
    "201311",
    "2013w46",
    "20131116"
  ]
}

【讨论】:

    猜你喜欢
    • 2016-03-20
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 2021-06-02
    • 1970-01-01
    • 2021-12-06
    • 1970-01-01
    • 2017-03-12
    相关资源
    最近更新 更多