MongoDB多条件$match与$group聚合查询问题及修正
问题分析与修正方案
原查询的核心问题
- 日期匹配错误:
$lt后使用字符串('2022-09-16')而非ISODate类型,无法匹配集合中的Date类型字段,这是返回空数组的直接原因。 - 分组逻辑偏离需求:没有按
agentId分组获取每个代理的最新记录,反而用createdAt作为分组ID,完全没实现“每个agent符合条件的最后一条postBalance”的目标。 - 过滤范围过窄:仅指定
type: "CASH_OUT",无法覆盖多类型汇总的需求。
修正后的聚合查询
db.transaction.aggregate([ // 1. 过滤日期范围(可按需添加指定type) { $match: { createdAt: { $gte: ISODate('2022-09-15'), $lt: ISODate('2022-09-16') // 必须用ISODate类型匹配Date字段 } // 如需限定交易类型,可添加:type: { $in: ["CASH_OUT", "FUNDS_TRANSFER", "AIRTIME_VTU"] } } }, // 2. 按agentId分组后,按createdAt降序排序,确保每个agent的最新记录排在最前 { $sort: { agentId: 1, createdAt: -1 } }, // 3. 按agentId分组,取每个agent的最新一条记录的type和postBalance { $group: { _id: "$agentId", latestType: { $first: "$type" }, latestPostBalance: { $first: "$postBalance" } } }, // 4. 按type分组,汇总对应类型的postBalance总和 { $group: { _id: "$latestType", total: { $sum: "$latestPostBalance" } } }, // 5. 转换为目标格式,添加日期字段 { $project: { _id: 0, type: "$_id", total: "$total" } }, { $group: { _id: null, date: { $first: ISODate('2022-09-15') }, // 可根据过滤条件动态生成,或固定值 typeTotals: { $push: { k: "$type", v: "$total" } } } }, { $replaceRoot: { newRoot: { $mergeObjects: [ { date: "$date" }, { $arrayToObject: "$typeTotals" } ] } } }, // 可选:将日期格式化为YYYY-MM-DD字符串 { $project: { date: { $dateToString: { format: "%Y-%m-%d", date: "$date" } }, CASH_OUT: 1, FUNDS_TRANSFER: 1, AIRTIME_VTU: 1 } } ])
关键步骤说明
- $match阶段:严格用
ISODate匹配日期,确保命中集合中的Date类型字段;若只需处理特定交易类型,添加$in条件即可。 - $sort阶段:先按
agentId升序、再按createdAt降序,保证每个agent的最新交易排在分组首位。 - 第一次$group:按
agentId分组,用$first获取每个agent的最新交易的type和postBalance。 - 第二次$group:按交易类型分组,对同类型下所有agent的最新postBalance求和。
- 格式转换阶段:通过
$arrayToObject和$replaceRoot将结果转换为你期望的键值对格式,同时添加日期字段。
注意事项
确保集合中所有目标文档都包含agentId字段(你提到记录包含该字段,样本可能遗漏),否则第一次分组会出错。
内容的提问来源于stack exchange,提问作者CuriousCat
相关产品推荐
相关产品推荐

