Doctrine ODM MongoDB聚合框架实现按类型、年月嵌套分组并聚合计数的问题
Doctrine ODM MongoDB聚合框架实现按类型、年月嵌套分组并聚合计数的问题
我明白你现在遇到的问题啦——当前的聚合逻辑只是把每个文档的年月数据直接推送到数组里,没有对同一年月的条目做合并统计。要实现先按类型分组,再在每个类型下按年月聚合计数的效果,我们需要分两次使用$group阶段来完成:
正确的聚合步骤
- 第一次分组:按类型+年月组合统计
先把所有文档按type、date提取出的year和month共同分组,统计每个组合下的文档数量。这一步会自动合并同类型同年月的所有文档,得到单一的计数结果。 - 第二次分组:按类型聚合年月统计结果
再将第一次分组的结果按type重新分组,把第一次分组得到的年月和count组合成对象,收集到byMonth数组中。
具体实现代码
$aggBuilder = $dm->createAggregationBuilder(Example::class); // 保留你原来的时间范围匹配逻辑 $aggBuilder->match() ->field('date') ->gte($from) ->lte($to); // 第一次分组:按 type + 年 + 月 组合分组,统计每个组合的文档数量 $aggBuilder->group() ->field('id') ->expression( $aggBuilder->expr() ->field('type') ->expression('$type') ->field('year') ->year('$date') ->field('month') ->month('$date') ) ->field('count') ->sum(1); // 第二次分组:仅按 type 分组,聚合年月统计结果到 byMonth 数组 $aggBuilder->group() ->field('id') ->expression( $aggBuilder->expr() ->field('type') ->expression('$id.type') ) ->field('byMonth') ->push( $aggBuilder->expr() ->field('month') ->expression('$id.month') ->field('year') ->expression('$id.year') ->field('count') ->expression('$count') ); // 执行聚合查询 $result = $aggBuilder->getQuery()->execute();
最终输出效果
执行上述代码后,你会得到和预期完全一致的结果:
array(2) { ["_id"]=> array(1) { ["type"]=> string(1) "A" } ["byMonth"]=> array(3) { [0]=> array(3) { ["month"]=> int(7) ["year"]=> int(2025) ["count"]=> int(2) } [1]=> array(3) { ["month"]=> int(3) ["year"]=> int(2025) ["count"]=> int(2) } [2]=> array(3) { ["month"]=> int(1) ["year"]=> int(2025) ["count"]=> int(1) } } } array(2) { ["_id"]=> array(1) { ["type"]=> string(1) "B" } ["byMonth"]=> array(1) { [0]=> array(3) { ["month"]=> int(2) ["year"]=> int(2025) ["count"]=> int(1) } } }
代码逻辑说明
- 第一次
$group阶段的_id同时包含type、year、month,确保每个唯一的组合只会生成一条统计记录,用sum(1)来累加该组合下的文档数量。 - 第二次
$group阶段仅按type分组,通过push将第一次分组得到的年月统计项整合到数组中,最终得到你想要的无重复嵌套分组结构。
内容来源于stack exchange
相关产品推荐
相关产品推荐

