MongoDB如何查询指定用户最近n个月数据且每月仅返回最后一条记录
MongoDB按用户查询近n个月每月最新记录解决方案
需求说明
查询指定用户最近n个月的数据,同一个月存在多条记录时仅返回当月最后一条存入的记录,最终结果按月份升序排列。
示例:n为3、userId为userId1时返回该用户最近3个月每个月的最新一条记录。
现有写法问题
你当前使用的普通find+limit逻辑只能返回最新的n条全量记录,若同一个月存在多条数据会返回多条同月结果,无法满足按月份去重的要求。
适配mongojs v4.1.2的实现代码
const queryMonthCount = 3; // 自定义查询的最近月份数 const targetUserId = 'userId1'; // 自定义目标用户ID db.collection(collection_name) .aggregate([ // 1. 前置筛选目标用户的所有记录,缩小后续计算范围 { $match: { userId: targetUserId } }, // 2. 统一将时间转为ISODate类型(如果你的processedAt已经是ISODate可省略此步) { $set: { processedAt: { $toDate: "$processedAt" } } }, // 3. 按时间倒序排列,保证同一个月的记录中最新的排在最前 { $sort: { processedAt: -1 } }, // 4. 按年月分组,每组取第一条即当月最新记录 { $group: { _id: { $dateToString: { format: "%Y-%m", date: "$processedAt" } }, latestDoc: { $first: "$$ROOT" } } }, // 5. 按年月倒序取最近的n个月数据 { $sort: { _id: -1 } }, { $limit: queryMonthCount }, // 6. 还原记录结构,去掉分组的包裹层 { $replaceRoot: { newRoot: "$latestDoc" } }, // 7. 最终按月份升序排列,符合返回要求 { $sort: { processedAt: 1 } }, // 可选:如果不需要返回_id可开启下方投影 // { $project: { _id: 0 } } ]) .toArray()
逻辑说明
- 前置
$match筛选可以大幅降低后续计算的数据量,提升查询性能 - 按时间倒序后分组取第一条的逻辑,避免了复杂的最大值匹配,兼容绝大多数MongoDB版本
- 两次排序分别满足「取最近n个月」和「最终结果按月升序返回」的要求
样例验证
样例输入
[ { "_id": "objectId(\"aaaaaa\")", "userId": "userId1", "processedAt": "2021-06-01T12:16:49.349Z" }, { "_id": "objectId(\"bbbbb\")", "userId": "userId1", "processedAt": "2021-10-11T12:16:49.349Z" }, { "_id": "objectId(\"ccccc\")", "userId": "userId1", "processedAt": "2021-10-25T12:16:49.349Z" }, { "_id": "objectId(\"eeeee\")", "userId": "userId1", "processedAt": "2021-09-12T12:16:49.349Z" }, { "_id": "objectId(\"fffff\")", "userId": "userId1", "processedAt": "2021-09-28T12:16:49.349Z" }, { "_id": "objectId(\"ggggg\")", "userId": "userId1", "processedAt": "2021-09-23T12:16:49.349Z" }, { "_id": "objectId(\"hhhhh\")", "userId": "userId1", "processedAt": "2021-07-23T12:16:49.349Z" }, { "_id": "objectId(\"iiiii\")", "userId": "userId2", "processedAt": "2021-09-29T12:16:49.349Z" }, { "_id": "objectId(\"jjjjj\")", "userId": "userId1", "processedAt": "2022-01-29T12:16:49.349Z" }, { "_id": "objectId(\"kkkkk\")", "userId": "userId1", "processedAt": "2022-02-29T12:16:49.349Z" } ]
样例输出
[ { "_id": "objectId(\"ccccc\")", "userId": "userId1", "processedAt": "2021-10-25T12:16:49.349Z" }, { "_id": "objectId(\"jjjjj\")", "userId": "userId1", "processedAt": "2022-01-29T12:16:49.349Z" }, { "_id": "objectId(\"kkkkk\")", "userId": "userId1", "processedAt": "2022-02-29T12:16:49.349Z" } ]
内容的提问来源于stack exchange,提问作者sham
相关产品推荐
相关产品推荐

