Mongo Aggregate:重复数组值字段的总计数字段

时间:2016-03-01 00:54:39

标签: mongodb aggregation-framework

我有很多文件:

{
  _id: '1',
  colors: [
    { value: 'red', count: 2 },
    { value: 'blue', count: 3}
  ]
  shapes: [
    { value: 'cube', type: '3d' },
    { value: 'square', type: '2d'}
  ]
},    
{
  _id: '2',
  colors: [
    { value: 'red', count: 7 },
    { value: 'blue', count: 34},
    { value: 'yellow', count: 12}
  ]
  shapes: [
    { value: 'prism', type: '3d' },
    { value: 'triangle', type: '2d'}
  ]
}

使用$unwind$addToSet,因此:

db.getCollection('coll').aggregate([{$unwind:"$colors"},{$unwind:"$shapes"},{$group:{_id:null,colors:{$addToSet:"$colors"},shapes:{$addToSet:"$shapes"}])

我可以得到以下内容:

{
    "_id" : null,
    "colors" : [ 
        { "value" : "red", "count" : 2 }, 
        { "value" : "blue", "count" : 3 }, 
        { "value" : "red", "count" : 7 }, 
        { "value" : "blue", "count" : 34 }, 
        { "value" : "yellow", "count" : 12 }
    ]
    "shapes" : [
        { value: 'cube', type: '3d' },
        { value: 'square', type: '2d'}
        { value: 'prism', type: '3d' },
        { value: 'triangle', type: '2d'}
    ]
}

我想要的是通过字段“值”来判断重复,并总结重复的“计数”字段,即

{
    "_id" : null,
    "colors" : [ 
        { "value" : "red", "count" : 9 }, 
        { "value" : "blue", "count" : 37 },  
        { "value" : "yellow", "count" : 12 }
    ]
    "shapes" : [
        { value: 'cube', type: '3d' },
        { value: 'square', type: '2d'}
        { value: 'prism', type: '3d' },
        { value: 'triangle', type: '2d'}
    ]
}

question表示我可以将$colors.value用作_id字段,将$sum用于count。但是,由于我有第二个数组$unwind和聚合/ $group,我不确定这样做的最佳方法。

2 个答案:

答案 0 :(得分:4)

尝试运行以下聚合管道:

pipeline = [
    {"$unwind": "$colors"},
    {
        "$group": {
            "_id": "$colors.value",
            "count": { "$sum": "$colors.count" },
            "shapes": { "$first": "$shapes" }
        }
    },
    {"$unwind": "$shapes"},
    {
        "$group": {
            "_id": null,
            "colors": { 
                "$addToSet": {
                    "value": "$_id",
                    "count": "$count"
                }
            },
            "shapes": { "$addToSet": "$shapes" }            
        }
    }
];
db.getCollection('coll').aggregate(pipeline)

示例输出

{
    "result" : [ 
        {
            "_id" : null,
            "colors" : [ 
                {
                    "value" : "red",
                    "count" : 9
                }, 
                {
                    "value" : "blue",
                    "count" : 37
                }, 
                {
                    "value" : "yellow",
                    "count" : 12
                }
            ],
            "shapes" : [ 
                {
                    "value" : "square",
                    "type" : "2d"
                }, 
                {
                    "value" : "cube",
                    "type" : "3d"
                }, 
                {
                    "value" : "triangle",
                    "type" : "2d"
                }, 
                {
                    "value" : "prism",
                    "type" : "3d"
                }
            ]
        }
    ],
    "ok" : 1
}

请注意,文档{ value: 'yellow', count: '12'}的计数值是一个字符串,在聚合中它将打折为0值,因为 $sum 运算符有效地聚合数值,否则字符串值将累积为零默认值。

$group管道中,您现在通过$colors.value字段对展平的颜色数组文档进行分组,然后使用累加器在分组的文档上返回所需的聚合。累加器运算符 $first 用于此分组操作,因为当文档按定义的顺序时,它会从每个组的第一个文档返回一个值,在这种情况下,您希望返回将所有文档分组时的形状字段。这是维护管道中文档顺序的一个技巧。

这里需要注意的一点是,在执行管道时,MongoDB会将运营商相互管道化。 "管"这里采用Linux的含义:运算符的输出成为以下运算符的输入。每个运算符的结果是一个新的文档集合。所以Mongo按如下方式执行上一个管道:

collection | $unwind | $group | $unwind | $group => result

因此, $first 是获取上一个管道到下一个管道的形状字段所必需的。

答案 1 :(得分:0)

因此,您需要重写插入,或将字符串转换为计数值的整数。

这是插入:

db.so.insert([{
  _id: '1',
  colors: [
    { value: 'red', count: 2 },
    { value: 'blue', count: 3}
  ]
},    
{
  _id: '2',
  colors: [
    { value: 'red', count: 7 },
    { value: 'blue', count: 34},
    { value: 'yellow', count: 12}
  ]
}]);

要在现有表格上进行转换,您可以look at this SO

然后你可以做一个简单的两步聚合查询:

db.so.aggregate(
  [
    {
      $unwind: "$colors"
    },
    {
      $group: {
       _id : { color : "$colors.value"},
       count : { $sum: "$colors.count"},
       simple : { $sum: 1}
      }
    }
  ]
);
相关问题