Mongoose查询最近5天未登录用户出现重复结果问题求解
问题原因
你遇到的两个核心问题:
- 原有聚合逻辑不符合「最近5天未登录」的查询需求:你先匹配了所有早于5天前的登录记录,如果一个用户最近5天有登录、同时存在更早的登录记录,也会被错误纳入结果。
- 新增的
$group阶段位置错误、字段配置缺失:你把$group放在$project之后,而之前的$project没有保留user字段,分组时$user取值为undefined,自然返回空数组;同时你只配置了_id字段,没有保留需要的用户信息和登录时间字段。
解决方案
场景1:仅查询有过登录记录、但最近5天未登录的用户
先按用户分组去重拿到最新登录时间,再做筛选和关联查询,代码如下:
const dateToCheck = new Date(); // 注意将环境变量转为数字,避免计算错误 dateToCheck.setDate(dateToCheck.getDate() - +process.env.LEASS_ACTIVE_USER_DAYS); const inactiveUsers = await UserActivity.aggregate([ // 按用户ID分组,取每个用户的最新登录时间,直接完成去重 { $group: { _id: "$user", lastLogin: { $max: "$date" } } }, // 筛选最新登录时间早于5天前的用户 { $match: { lastLogin: { $lt: dateToCheck } } }, // 关联用户表取用户信息 { $lookup: { from: "users", localField: "_id", foreignField: "_id", as: "userdata" } }, { $unwind: "$userdata" }, // 自定义返回字段 { $project: { _id: 0, userId: "$_id", firstName: "$userdata.firstName", lastName: "$userdata.lastName", username: "$userdata.username", lastLogin: 1 } } ]);
场景2:需要包含从未有过登录记录的用户
直接从用户表出发做聚合,代码如下:
const dateToCheck = new Date(); dateToCheck.setDate(dateToCheck.getDate() - +process.env.LEASS_ACTIVE_USER_DAYS); const inactiveUsers = await User.aggregate([ // 关联用户的所有登录记录 { $lookup: { from: "useractivities", // 注意替换为你实际的useractivity集合名,mongoose默认会转小写复数 localField: "_id", foreignField: "user", as: "loginRecords" } }, // 计算用户最新登录时间 { $addFields: { lastLogin: { $max: "$loginRecords.date" } } }, // 筛选条件:无登录记录 或 最新登录时间早于5天前 { $match: { $or: [ { lastLogin: { $exists: false } }, { lastLogin: { $lt: dateToCheck } } ] } }, // 自定义返回字段 { $project: { firstName: 1, lastName: 1, username: 1, lastLogin: 1 } } ]);
内容的提问来源于stack exchange,提问作者Paritosh Mahale
相关产品推荐
相关产品推荐

