You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Mongoose中使用pre中间件实现多级关联记录级联删除

你原来的实现存在两个核心问题:1. 没有等待异步删除操作完成就调用next(),大概率会出现数据不一致;2. 缺少Agreement的关联删除逻辑。以下是可直接运行的完善方案:

方案1:分层配置中间件(推荐)

该方案逻辑解耦,后续单独删除Room时也会自动清理关联的Agreement,可维护性更强。

第一步:给RoomSchema添加deleteMany前置钩子

RoomSchema.pre("deleteMany", async function (next) {
  // 获取当前要删除的所有Room ID列表
  const roomIds = await Room.find(this.getFilter()).distinct("_id").exec();
  // 批量删除这些Room关联的所有Agreement
  await Agreement.deleteMany({ room: { $in: roomIds } }).exec();
  next();
});

第二步:修改BuildingSchema的deleteOne前置钩子,增加异步等待

BuildingSchema.pre("deleteOne", async function (next) {
  // 兼容query级别和document级别的deleteOne调用
  const buildingId = this.getFilter ? this.getFilter()._id : this._id;
  // 触发Room的deleteMany,自动执行上面对应的Agreement删除逻辑
  await Room.deleteMany({ building: buildingId }).exec();
  next();
});

方案2:单中间件一次性处理

适合不需要单独处理Room删除逻辑的场景,所有关联清理逻辑都收敛在Building的删除钩子中:

BuildingSchema.pre("deleteOne", async function (next) {
  const buildingId = this.getFilter ? this.getFilter()._id : this._id;
  // 1. 查询该建筑下所有房间ID
  const roomIds = await Room.find({ building: buildingId }).distinct("_id").exec();
  // 2. 删除这些房间关联的所有合同
  await Agreement.deleteMany({ room: { $in: roomIds } }).exec();
  // 3. 删除所有关联房间
  await Room.deleteMany({ building: buildingId }).exec();
  next();
});

额外适配说明

如果业务中还会用到findOneAndDelete、deleteMany等方法删除Building,需要把钩子的触发事件扩展为对应事件列表,同时适配多建筑删除的逻辑:

BuildingSchema.pre(["deleteOne", "findOneAndDelete", "deleteMany"], async function (next) {
  // 处理批量删除Building的场景
  if (this.op === "deleteMany") {
    const buildingIds = await Building.find(this.getFilter()).distinct("_id").exec();
    const roomIds = await Room.find({ building: { $in: buildingIds } }).distinct("_id").exec();
    await Agreement.deleteMany({ room: { $in: roomIds } }).exec();
    await Room.deleteMany({ building: { $in: buildingIds } }).exec();
  } else {
    // 单个删除逻辑
    const buildingId = this.getFilter ? this.getFilter()._id : this._id;
    const roomIds = await Room.find({ building: buildingId }).distinct("_id").exec();
    await Agreement.deleteMany({ room: { $in: roomIds } }).exec();
    await Room.deleteMany({ building: buildingId }).exec();
  }
  next();
});

内容的提问来源于stack exchange,提问作者Justin Timbersaw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 12:06:04