【问题标题】:How to specify the original parameters without making any changes in the keyf function of the aggregation group如何在不改变聚合组的keyf函数的情况下指定原始参数
【发布时间】:2017-06-06 01:13:48
【问题描述】:

这是我开始的简化集合:

[{
  "_id" : ObjectId("577a598ecab5bb4a002c19da"),
  "user" : ObjectId("5775549f9fcaae26c9149026"),
  "expense" : 12.87,
  "created" : ISODate("2016-07-04T12:43:07.181Z")
},
{
  "_id" : ObjectId("577a598ecab5bb4a002c19db"),
  "user" : ObjectId("5775549f9fcaae26c9149026"),
  "expense" : 12.87,
  "created" : ISODate("2016-07-06T12:10:07.181Z")
},
{
  "_id" : ObjectId("977a598ecai6bb4a002c19du"),
  "user" : ObjectId("6775539f9fciae26c9149027"),
  "expense" : 12.87,
  "created" : ISODate("2016-07-07T10:43:07.181Z")
},
....
]

我想group 并计算created 参数的特定日期的所有users

我正在尝试,但它不起作用:

db.getCollection('expenses').group({
            keyf: function(doc) {
               return { 
                   "day_created": doc.created.getDate(),
                   "user" : doc.user // or  "user" : 1
                }
            },
            cond: {},
            reduce: function (value, result) {
                result.total++;  
            },
            initial: {
                total: 0
            }
 });

相反,各个组完美地工作(日期):

db.getCollection('expenses').group({
            keyf: function(doc) {
               return { 
                   "day_created": doc.created.getDate()
                }
            },
            cond: {},
            reduce: function (value, result) {
                result.total++;  
            },
            initial: {
                total: 0
            }
 });

回应

[
    {
        "day_created" : 17,
        "total" : 5385
    },
    {
        "day_created" : 18,
        "total" : 6338
    },
 ....
]

相反,各个组完美地工作(对于用户):

db.getCollection('tickets').group({
            key : {user : 1},
            cond: {},
            reduce: function (value, result) {
                result.total++;  
            },
            initial: {
                total: 0
            }
 });

回应

[
    {
        "user" : ObjectId("5776f0143543e84a003d53bf"),
        "total" : 155
    },
    {
        "user" : ObjectId("577554a89fcaae26c914a8bd"),
        "total" : 494
    },
...
]

我正在使用 MongoDB shell 版本:3.2.1。如何使用计算字段进行组聚合而其他人不这样做?

【问题讨论】:

  • 上述示例文档的预期输出是什么?
  • 我的预期输出:[ { "user" : ObjectId("5776f0143543e84a003d53bf"), "day_created" : 17, "total" : 155 }, { "user" : ObjectId("577554a89fcaae26c914a8bd"), "day_created" : 17, "total" : 494 }, ... ]
  • 这是所需聚合操作的预期结果“对创建参数的特定日期的所有用户进行分组和计数。”?
  • yes "对创建参数的特定日期的所有用户进行分组和统计。"

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

您可以使用聚合框架代替 group 函数来获取所需的聚合。考虑运行以下管道:

db.getCollection('expenses').aggregate([
    {
        "$project": {
            "day_created": { 
                "$dateToString": { 
                    "format": "%Y-%m-%d", 
                    "date": "$created" 
                } 
            },
            "user": 1
        }
    },
    {
        "$group": {
            "_id": {
                "day_created": "$day_created",
                "user": "$user"
            },
            "total": { "$sum": 1 }
        }
    },
    {
        "$project": {
            "_id": 0
            "user": "$_id.user",
            "day_created": "$_id.day_created",
            "total": 1
        }
    }
])

在上述管道中,第一个 $project 步骤将使用 $dateToString 运算符创建 day_created 字段。下一个 $group 管道将按 user 和新创建的 day_created 字段这两个键对文档进行分组,并使用 $sum 计算聚合。

最后一个 $project 管道步骤然后重塑字段以输出所需的 JSON 结构。


要解决您的问题,您需要将 created 日期转换为唯一代表日期的日期格式。

尝试运行以下命令:

db.getCollection('expenses').group({
    keyf: function(doc) {
        var month = '' + (doc.created.getMonth() + 1),
        day = '' + doc.created.getDate(),
        year = doc.created.getFullYear();

        if (month.length < 2) month = '0' + month;
        if (day.length < 2) day = '0' + day;

        var day_created = [year, month, day].join('-');
        return { 
            "day_created": day_created,
            "user" : doc.user 
        }
    },
    cond: {},
    reduce: function (value, result) {
        result.total++;  
    },
    initial: {
        total: 0
    }
})

【讨论】:

  • 感谢这个解决方案,但我会使用方法db.collection.group()
  • 只是出于好奇,当聚合框架的$group 工作得一样好,效率更高时,为什么还要使用db.collection.group()?因为db.collection.group() 使用JavaScript,所以它受到许多性能限制。在大多数情况下,聚合管道中的 $group 运算符提供了一个限制较少的合适替代方案。
  • 感谢您的回答,now I'm using the aggregation 因为问题与组的语法无关,而是size of my collection 所以:这项工作返回 { "day_created": doc.created.getDate( ), "user" : doc.user // 或 "user" : 1 } 但我有这个错误: [thread1] 错误: group command failed: { "waitedMS" : NumberLong(0), "ok" : 0, "errmsg" : "errmsg: \"group() can't handle more than 20000 unique keys\"", "code" : 2 }
  • 那个限制是documented
猜你喜欢
  • 1970-01-01
  • 2019-10-26
  • 2021-12-02
  • 2012-03-24
  • 2017-09-29
  • 2021-06-09
  • 1970-01-01
  • 1970-01-01
  • 2019-10-03
相关资源
最近更新 更多