MongoDB如何通过._id过滤已点赞/点踩用户账号?适配交友应用场景
问题根因分析
- 逻辑分支错误:原过滤函数使用
if (存在点赞记录) {} else if (存在点踩记录) {}的分支结构,只要用户有过点赞记录,就完全不会执行点踩记录的过滤逻辑,反过来也一样,导致大量已操作的用户没有被正确过滤。 - 遍历修改原数组导致索引异常:用for of遍历原数组的同时调用splice删除元素,数组长度会动态变化,后续遍历的索引会发生偏移,最终出现误删未操作过的用户、漏删已操作用户的问题。
- 未统一返回响应:过滤完成后没有主动返回结果给前端,只有当用户既没有点赞也没有点踩记录的时候才会返回数据,其余情况前端无法拿到正常响应。
- 执行效率低:双层循环的时间复杂度为O(n*m),用户量大的时候运算性能会非常差。
修复方案
方案1:修复现有过滤函数
如果要保留独立过滤函数的写法,可直接替换为以下代码:
const filter = async (currentUser, users, req, res, error) => { try { // 合并所有需要排除的用户ID存入Set,存在性判断时间复杂度为O(1) const excludedIds = new Set([ ...currentUser.likes, ...currentUser.dislikes ]); // 直接过滤生成新数组,不修改原数组,彻底避免索引错乱问题 const filteredUsers = users.filter(user => !excludedIds.has(user._id.toString())); // 统一返回过滤后的结果 return res.json({ users: filteredUsers }); } catch (error) { console.log(error, "error"); return res.status(500).json({msg: "用户过滤失败"}); } };
方案2:MongoDB查询阶段直接过滤(更优,推荐)
不需要单独维护过滤函数,直接在数据库查询阶段排除已点赞/点踩的用户,减少无效数据查询和传输,数据量越大性能优势越明显:
router.get( "/user/match/:id", authenticateUser, asyncHandler(async (req, res, error) => { const currentUser = await User.findOne({ _id: req.params.id }); if (currentUser.gender === "Male" && currentUser.sexualPreference === "Straight") { // 合并所有需要排除的用户ID const excludedIds = [...currentUser.likes, ...currentUser.dislikes]; // 用MongoDB的$nin操作符直接过滤掉不需要展示的用户 const users = await User.find({ gender: "Female", sexualPreference: "Straight", _id: { $nin: excludedIds } }); return res.json({ users }); } // 可在此扩展其他性别/性取向的匹配逻辑 return res.status(400).json({msg: "暂不支持该匹配条件"}); }) );
内容的提问来源于stack exchange,提问作者RandyBeans
相关产品推荐
相关产品推荐

