Mongoose多$or条件查询问题:社交应用排除已关联推荐用户
解决方案
首先,你原查询的核心问题是重复使用$or操作符导致逻辑被覆盖——MongoDB查询对象中同名键会被后面的覆盖,所以第二个$or直接替换了第一个,导致查询逻辑完全偏离预期。
下面是两种高效实现需求的方案:
方案一:用聚合查询一次性获取所有需排除的用户ID
先找出所有和当前用户存在邀请关联(发送/接收邀请)的用户ID,再直接从用户集合中排除这些ID:
const id = req.id; // 1. 获取所有与当前用户有邀请关联的用户ID const relatedUserIds = await Follower.aggregate([ { $match: { $or: [ { sent: id }, // 当前用户发出邀请的对象 { received: id } // 给当前用户发邀请的对象 ] } }, { $project: { // 判断当前用户是发送方还是接收方,提取对方ID userId: { $cond: [{ $eq: ['$sent', id] }, '$received', '$sent'] } } }, { $group: { _id: null, ids: { $addToSet: '$userId' } } } // 去重合并 ]); // 整理需排除的ID:关联用户ID + 当前用户自己 const excludeIds = relatedUserIds.length ? relatedUserIds[0].ids : []; excludeIds.push(id); // 2. 查询推荐用户:排除当前用户和所有关联用户,取前100个 const recommendedUsers = await User.find({ _id: { $nin: excludeIds } }).limit(100);
方案二:用distinct简化关联ID查询
如果觉得聚合查询复杂,可以用distinct分别获取两类关联用户ID,再合并去重:
const id = req.id; // 获取当前用户发送邀请的对象ID const sentToIds = await Follower.distinct('received', { sent: id }); // 获取给当前用户发送邀请的对象ID const receivedFromIds = await Follower.distinct('sent', { received: id }); // 合并去重,加上当前用户ID作为排除列表 const excludeIds = [...new Set([...sentToIds, ...receivedFromIds, id])]; // 查询推荐用户 const recommendedUsers = await User.find({ _id: { $nin: excludeIds } }).limit(100);
原代码问题复盘
- 重复
$or被覆盖:原查询中两个$or会被MongoDB视为同一键,最终只有第二个$or生效,逻辑完全错误。 - 低效的分步查询:先取100个非当前用户再排除,容易出现排除后无结果的情况,不如直接从源头过滤更高效。
内容的提问来源于stack exchange,提问作者user22453190
相关产品推荐
相关产品推荐

