MongoDB分组聚合:获取$max值及其计数与占比,含关联字段需求
解决MongoDB聚合中关联字段name缺失的问题
嘿,我看到你现在的问题是分组聚合后,l1字段的关联name没出现在结果里——这是因为原来的聚合流程没有把关联集合的name数据拉进来,毕竟Mongoose的populate()没法直接在聚合管道里用,得用MongoDB原生的$lookup来做关联查询。我来帮你调整聚合语句,同时满足你要的最大值、出现次数和占比需求:
完整聚合语句
db.getCollection("test").aggregate([ // 第一步:匹配目标文档 { "$match": { "doc_id": 1.0 } }, // 第二步:关联l1对应的集合,拉取name字段(替换成你的l1集合真实名称) { "$lookup": { "from": "l1_collection", "localField": "l1", "foreignField": "_id", "as": "l1_info" } }, // 展开关联后的数组(因为lookup返回的是数组,每个文档只关联一个l1所以直接unwind) { "$unwind": "$l1_info" }, // 第三步:按name分组,同时保存必要的统计数据和l1的详细信息 { "$group": { "_id": { "name": "$name" }, "total": { "$sum": "$amount" }, "group_total_count": { "$sum": 1 }, // 分组内的总记录数 "l1_max_id": { "$max": "$l1" }, // 分组内l1的最大值(id) // 保存每个l1的id和对应的name,方便后续过滤 "l1_details": { "$push": { "id": "$l1", "name": "$l1_info.name" } } } }, // 第四步:格式化结果,提取max对应的name、计算次数和占比,甚至生成你要的显示文本 { "$project": { "_id": 1, "total": 1, "l1": { "_id": "$l1_max_id", "name": { // 从l1_details里过滤出id等于max的项,取出name "$arrayElemAt": [ { "$map": { "input": { "$filter": { "input": "$l1_details", "cond": { "$eq": ["$$this.id", "$l1_max_id"] } } }, "as": "item", "in": "$$item.name" } }, 0 ] }, "count": { // 计算max l1在分组内的出现次数 "$size": { "$filter": { "input": "$l1_details", "cond": { "$eq": ["$$this.id", "$l1_max_id"] } } } }, "percent": { // 计算占比(次数/分组总记录数) "$divide": [ { "$size": { "$filter": { "input": "$l1_details", "cond": { "$eq": ["$$this.id", "$l1_max_id"] } } } }, "$group_total_count" ] } }, // 可选:生成你要的格式化显示文本,比如 'IT - (25%) Total 4/16' "l1_display": { "$concat": [ { "$arrayElemAt": [ { "$map": { "input": { "$filter": { "input": "$l1_details", "cond": { "$eq": ["$$this.id", "$l1_max_id"] } } }, "as": "item", "in": "$$item.name" } }, 0 ] }, " - (", { "$toString": { "$multiply": ["$l1.percent", 100] } }, "%) Total ", { "$toString": "$l1.count" }, "/", { "$toString": "$group_total_count" } ] } } } ]);
关键步骤说明
- $lookup + $unwind:这是核心,把l1关联集合里的name字段拉到当前聚合流程中,解决了关联字段缺失的问题。记得把
from的值替换成你实际存储l1数据的集合名称。 - 分组阶段的l1_details:保存每个分组内所有l1的id和name,这样后续才能找到最大值对应的name,同时统计出现次数。
- project阶段的过滤与计算:通过
$filter筛选出对应max id的l1项,用$arrayElemAt取出name;用$size统计出现次数;用$divide计算占比,最后还可以用$concat生成你需要的格式化显示文本。
示例返回结果
{ "_id": { "name": "xzy" }, "total": 35.0, "l1": { "_id": "4343920239201W", "name": "IT", "count": 4.0, "percent": 0.25 }, "l1_display": "IT - (25%) Total 4/16" }
内容的提问来源于stack exchange,提问作者Vikash
相关产品推荐
相关产品推荐

