如何编写MongoDB aggregate聚合查询实现按用户分组统计通话邮件数据
MongoDB 聚合查询解决方案
你原来编写的聚合语句存在以下核心问题:
- 连续两次使用
$group语法错误,第一次$group仅保留了userId字段,后续阶段无法获取timestamp、type、platform等所需字段 - 后续的
$project和$count完全不符合你要整理分类数据的需求
正确聚合语句
const targetGroupId = "6132a0cb74af9d82df74e918"; // 替换为你要查询的groupId db.collection.aggregate([ // 第一阶段:筛选指定groupId的所有数据 { $match: { groupId: targetGroupId } }, // 第二阶段:按userId分组,分别收集该用户的call和email记录 { $group: { _id: "$userId", calls: { $push: { $cond: { if: { $eq: ["$type", "call"] }, then: { k: "$timestamp", v: { platform: "$platform" } }, else: "$$REMOVE" // 不符合type的直接排除 } } }, emails: { $push: { $cond: { if: { $eq: ["$type", "email"] }, then: { k: "$timestamp", v: { platform: "$platform" } }, else: "$$REMOVE" } } } } }, // 第三阶段:将calls和emails的数组合并为以timestamp为键的对象 { $project: { _id: 0, userId: "$_id", calls: { $arrayToObject: "$calls" }, emails: { $arrayToObject: "$emails" } } }, // 第四阶段:把所有用户数据合并到同一个文档,携带groupId信息 { $group: { _id: null, groupId: { $first: targetGroupId }, users: { $push: { k: "$userId", v: { calls: "$calls", emails: "$emails" } } } } }, // 第五阶段:将用户数组合并为以userId为键的对象,符合你期望的结构 { $project: { _id: 0, groupId: 1, userData: { $arrayToObject: "$users" } } } ]).exec()
输出结构说明
最终返回的结构如下(修正了你示例中数组用字符串键的语法错误,实际为对象结构):
{ "groupId": "6132a0cb74af9d82df74e918", "userData": { "6132a04892559282c40fd29a": { "calls": { "2021-09-01": { "platform": "yahoo" }, "2021-09-04": { "platform": "yahoo" } }, "emails": { "2021-09-01": { "platform": "google" }, "2021-09-04": { "platform": "google" } } }, "6132a04892559282c40ff2a9": { "calls": { "2021-09-04": { "platform": "yahoo" } }, "emails": { "1632958029720": { "platform": "google" } } } } }
关键操作符说明
$cond:条件判断,用来区分call和email两种类型的记录$$REMOVE:聚合系统变量,不符合条件的字段直接排除,不会进入结果数组$arrayToObject:将[ {k:xxx, v:xxx} ]格式的数组转换为键值对对象,实现以timestamp、userId为键的需求
内容的提问来源于stack exchange,提问作者Thorai219
相关产品推荐
相关产品推荐

