MongoDB:groupby子文档和count + add总计数

时间:2016-02-03 13:42:48

标签: mongodb mongodb-query aggregation-framework nosql

我想要实现的目标

假设有以下子文档:

{
    "id":1,
    "url":"mysite.com",
    "views": 
     [
       {"ip":"1.1.1.1","date":"01-01-2015"},
       {"ip":"2.2.2.2","date":"01-01-2015"},
       {"ip":"1.1.1.1","date":"01-01-2015"},
       {"ip":"1.1.1.1","date":"01-01-2015"}
     ]
}

我想算一下:

  1. 基于"ip"
  2. 的IP数量
  3. 还会计算"views"
  4. 中的子文档总数

    如果可能在同一查询中,以实现以下结果:

    [  
      {  
        "_id":"2.2.2.2",
        "count":1
      },
      {  
        "_id":"1.1.1.1",
        "count":3
      },
      {  
        "_id":"total",
        "count":4
      }
    ]
    

    到目前为止我取得的成就

    使用 MongoDB聚合框架,我已设法通过以下方式实现 1 点:

    db.collection.aggregate([
        {
            "$unwind": "$views"
        },
        {
            "$group": {
                "_id": "$views.ip",
                "count": {
                    "$sum": 1
                }
            }
        }
    ])
    

    返回:

    [  
      {  
        "_id":"2.2.2.2",
        "count":1
      },
      {  
        "_id":"1.1.1.1",
        "count":3
      }
    ]
    

    我希望在数组中返回额外的doc,即:

    {  
      "_id":"total",
      "count":4
    }
    

    实现我上面暴露的内容,但我被困在那里并且无法这样做。

1 个答案:

答案 0 :(得分:1)

在相同的聚合管道中不可能原则上管道在处理文件时对文件进行处理,即管道阶段不需要为每个输入文档生成一个输出文档;例如,某些阶段可以生成新文档或过滤掉文档。在上面的方案中,添加另一个 $group 步骤以获取分组的IP计数+总计数将产生与您所追求的不同的结果,即

db.collection.aggregate([
    {
        "$unwind": "$views"
    },
    {
        "$group": {
            "_id": "$views.ip",
            "count": {
                "$sum": 1
            }
        }
    },
    {
        "$group": {
            "_id": null,
            "total": {
                "$sum": "$count"
            }
        }
    }
])

您将只获得总数,因为 $group 会消耗所有输入文档(包含分组IP计数的文档),并为每个不同的组输出一个文档。额外的组步骤将对上一个流中的所有文档进行分组。

但是,您可以获得总计数,但作为最终结果中每个分组文档中的额外字段。以下使用初始$project管道阶段通过 $size 运算符获取总计数的示例可以实现此目的:

db.collection.aggregate([
    {
        "$project": {
            "views": 1,
            "views_size": { "$size": "$views" }
        }
    }
    {
        "$unwind": "$views"
    },
    {
        "$group": {
            "_id": "$views.ip",
            "count": {
                "$sum": 1
            },
            "total": { "$first": "$views_size" }
        }
    }
])

示例输出

[  
  {  
    "_id": "2.2.2.2",
    "count": 1,
    "total": 4
  },
  {  
    "_id": "1.1.1.1",
    "count": 3,
    "total": 4
  }
]