【问题标题】:Mongo Aggregate: Sum Count Field of Duplicate Array Value FieldMongo Aggregate:重复数组值字段的总和计数字段
【发布时间】:2016-06-13 06:30:38
【问题描述】:

我有一大堆这样的文件:

{
  _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,所以我不确定最好的方法。

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    尝试运行以下聚合管道:

    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 是从上一个管道到下一个管道获取形状字段所必需的。

    【讨论】:

    • 这看起来不错。让我试试看!我还编辑了我的帖子以删除错误的撇号 -_- 大量错别字!非常感谢! :) @chridam
    • Erm,你能解释一下这是做什么的吗?:"shapes": { "$first": "$shapes" }我可能在误解下运作......:3
    • @Tacocat 添加了一些解释,希望您能理解它在管道中的使用。在这里,它更多地使用了一种机制,将shapes字段从前一个管道中获取到分组中,而不影响当前的聚合。
    【解决方案2】:

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

    这里是插入:

    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}
          }
        }
      ]
    );
    

    【讨论】:

    • 我已经编辑了我的帖子以去掉撇号。那些是错别字。不幸的是,这实际上并没有回答我的问题。我知道我可以将$colors.value 用作_id。但是,这里的问题是我希望保留和汇总我的 shapes 字段,我不确定实现这一目标的最佳方法是什么,@Nicolas Modrzyk
    猜你喜欢
    • 2020-04-24
    • 1970-01-01
    • 2022-12-10
    • 2016-11-27
    • 2011-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多