如何使用Mongoose实现删除用户后双方列表互不可见功能
双向删除后用户列表互不可见实现方案
你现有Schema设计的deleteList(存储当前用户主动删除的用户ID)、beenDeletedList(存储主动删除了当前用户的用户ID)两个字段完全可以满足需求,只需要补全删除操作的双向写入逻辑、列表查询的过滤规则即可。
一、修复现有Schema的导出错误
你当前Schema代码存在变量不匹配问题,定义的Model常量名为User,最后导出时写的是不存在的UserInfo,需要先修正:
const mongoose = require("mongoose"); const userSchema = new mongoose.Schema( { userName: { type: String, }, deleteList: [{ type: mongoose.Types.ObjectId, ref: "User" }], beenDeletedList: [{ type: mongoose.Types.ObjectId, ref: "User" }], } ); const User = mongoose.model("User", userSchema); // 修正导出变量 module.exports = User;
二、补全删除操作的双向写入逻辑
当用户A删除用户B时,必须同时更新两个用户的关联列表,否则会出现单向屏蔽的异常,建议用MongoDB事务保证两个操作的原子性:
// 用户删除接口逻辑 exports.deleteUser = async (req, res, next) => { const { currentUserId, targetUserId } = req.body; const session = await mongoose.startSession(); session.startTransaction(); try { // 给当前操作的用户追加删除记录,用$addToSet避免重复插入相同ID await User.findByIdAndUpdate( currentUserId, { $addToSet: { deleteList: targetUserId } }, { session } ); // 给被删除的用户追加被删记录 await User.findByIdAndUpdate( targetUserId, { $addToSet: { beenDeletedList: currentUserId } }, { session } ); await session.commitTransaction(); res.send({ code: 200, msg: "删除成功" }); } catch (err) { await session.abortTransaction(); next(err); } finally { session.endSession(); } }
三、补全可见用户列表的过滤逻辑
列表需要排除三类用户:
- 当前用户主动删除的用户(存在
deleteList中) - 主动删除了当前用户的用户(存在
beenDeletedList中) - 当前登录用户自身
直接在数据库查询层面用$nin过滤即可,不要查全量数据后在内存过滤,性能更高。补全后的getSortedUsers代码如下:
exports.getSortedUsers = async (req, res, next) => { const currentUserId = req.body._id; // 仅查询需要用到的两个屏蔽列表字段,减少不必要的字段查询 const currentUser = await User.findById(currentUserId).select("deleteList beenDeletedList"); if (!currentUser) { return res.status(401).send({ code: 401, msg: "当前登录用户不存在" }); } // 合并所有需要屏蔽的用户ID const blockUserIds = [ ...currentUser.deleteList, ...currentUser.beenDeletedList, currentUserId ]; // 查询所有不在屏蔽列表中的用户,可根据业务需求追加sort排序规则 const visibleUserList = await User.find({ _id: { $nin: blockUserIds } }).select("userName _id"); // 仅返回列表需要展示的字段,降低传输开销 res.send({ code: 200, data: visibleUserList }); }
实现注意事项
- 所有数组追加ID的操作统一用
$addToSet,不要用$push,避免重复存储同一个用户ID造成数据冗余 - 删除操作必须加事务,防止服务异常中断导致只更新了单边数据,出现屏蔽逻辑不一致的问题
- 如果后续需要做取消删除/恢复好友功能,对应操作也要同步更新两个用户的
deleteList和beenDeletedList,把对应ID从数组中移除即可
内容的提问来源于stack exchange,提问作者Yellow Clock
相关产品推荐
相关产品推荐

