使用嵌套聚合进行计数

时间:2017-04-11 19:04:22

标签: mongodb mongoose

我一直在尝试对统计信息页面的注册收集数据进行分组和统计,以及进行动态注册,但我无法将其计入多个分组。 样本注册收集数据:

{
        "_id" : ObjectId("58ec60078cc818505fb75ace"),
        "event" : "Women's BB",
        "day" : "Saturday",
        "group" : "nonpro",
        "division" : "Women's",
        "level" : "BB"
}
{
        "_id" : ObjectId("58ec60078cc818505fb75acf"),
        "event" : "Coed BB",
        "day" : "Sunday",
        "group" : "nonpro",
        "division" : "Coed",
        "level" : "BB"
}
{
        "_id" : ObjectId("58ec60098cc818505fb75ad0"),
        "event" : "Men's BB",
        "day" : "Saturday",
        "group" : "nonpro",
        "division" : "Men's",
        "level" : "BB"
}
{
        "_id" : ObjectId("58ec60168cc818505fb75ad1"),
        "event" : "Men's B",
        "day" : "Saturday",
        "group" : "nonpro",
        "division" : "Men's",
        "level" : "B"
}
{
        "_id" : ObjectId("58ec60178cc818505fb75ad2"),
        "event" : "Women's Open",
        "day" : "Saturday",
        "group" : "pro",
        "division" : "Women's",
        "level" : "Pro"
}
{
        "_id" : ObjectId("58ec60188cc818505fb75ad3"),
        "event" : "Men's Open",
        "day" : "Saturday",
        "group" : "pro",
        "division" : "Men's",
        "level" : "Pro"
}

我想重新组织它并重新计算这样的事情:

[ {_id: { day: "Saturday", group: "nonpro" },
  count: 3,
  divisions: [
    { division: "Men's",
      count: 2,
      levels: [ 
          { level: "BB", count: 1 },
          { level: "B", count: 1 }]
    },
    { division: "Women's",
      count: 1,
      levels: [ 
          { level: "BB", count: 1 }]
    }
 },
{_id: { day: "Saturday", group: "pro" },
  count: 2,
  divisions: [
    { division: "Men's",
      count: 1,
      levels: [ 
          { level: "Pro", count: 1 }
    },
    { division: "Women's",
      count: 1,
      levels: [ 
          { level: "Pro", count: 1 }]
    }
 },
{_id: { day: "Sunday", group: "nonpro" },
  count: 1,
  divisions: [
    { division: "Coed",
      count: 1,
      levels: [ 
          { level: "BB", count: 1 }
    }
 }]

我知道我应该使用aggregate()函数,但是很难让它与count一起工作。这是我的聚合到目前为止的样子:

Registration
   .aggregate( 
  { $group: { 
      _id:   { day: "$day", group: "$group" }, 
      events: { $addToSet: { division: "$division", level: "$level"} },
      total: { $sum: 1}
    } 
  })

这会返回每天/每组组合的总注册次数,但如果我尝试将总数:{$ sum:1}添加到事件集中,我只会获得1(这是有道理的)。有没有办法让这个工作在一个数据库调用中,或者我是否需要为我需要的每个级别的分组单独进行?

1 个答案:

答案 0 :(得分:1)

您基本上需要3个级别的 $group 管道阶段。第一个将按所有四个键分组文档,即daygroupdivisionlevel。汇总组的计数 这将是level的计数。

前面的组将使用三个键,即daygroupdivision,聚合计数将对先前的组计数求和以及创建levels数组。

最后一组将是daygroup键+ divisions列表,其中嵌入了上一组的结果。

考虑为预期结果运行以下管道:

Registration.aggregate([
    {
        "$group": {
            "_id": { 
                "day": "$day", 
                "group": "$group",
                "division": "$division",
                "level": "$level"
            },
            "count": { "$sum": 1 }
        }
    },
    {
        "$group": {
            "_id": { 
                "day": "$_id.day", 
                "group": "$_id.group",
                "division": "$_id.division"                
            },
            "count": { "$sum": "$count" },
            "levels": {
                "$push": {
                    "level": "$_id.level",
                    "count": "$count"
                }
            }
        }
    },
    {
        "$group": {
            "_id": { 
                "day": "$_id.day", 
                "group": "$_id.group"             
            },
            "count": { "$sum": "$count" },
            "divisions": {
                "$push": {
                    "division": "$_id.division",
                    "count": "$count",
                    "levels": "$levels"
                }
            }
        }
    }
], (err, results) => {
    if (err) throw err;
    console.log(JSON.stringify(results, null, 4));
})

示例输出

/* 1 */
{
    "_id" : {
        "day" : "Saturday",
        "group" : "nonpro"
    },
    "count" : 3,
    "divisions" : [ 
        {
            "division" : "Women's",
            "count" : 1,
            "levels" : [ 
                {
                    "level" : "BB",
                    "count" : 1
                }
            ]
        }, 
        {
            "division" : "Men's",
            "count" : 2,
            "levels" : [ 
                {
                    "level" : "BB",
                    "count" : 1
                }, 
                {
                    "level" : "B",
                    "count" : 1
                }
            ]
        }
    ]
}

/* 2 */
{
    "_id" : {
        "day" : "Saturday",
        "group" : "pro"
    },
    "count" : 2,
    "divisions" : [ 
        {
            "division" : "Women's",
            "count" : 1,
            "levels" : [ 
                {
                    "level" : "Pro",
                    "count" : 1
                }
            ]
        }, 
        {
            "division" : "Men's",
            "count" : 1,
            "levels" : [ 
                {
                    "level" : "Pro",
                    "count" : 1
                }
            ]
        }
    ]
}

/* 3 */
{
    "_id" : {
        "day" : "Sunday",
        "group" : "nonpro"
    },
    "count" : 1,
    "divisions" : [ 
        {
            "division" : "Coed",
            "count" : 1,
            "levels" : [ 
                {
                    "level" : "BB",
                    "count" : 1
                }
            ]
        }
    ]
}