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

如何在Mongoose Schema验证器中获取Mongoose事务Session

Mongoose关联引用校验中访问事务会话的实现方案

问题根因

  • 示例代码中使用箭头函数定义自定义验证器,由于箭头函数不绑定自身的this,会继承外层词法作用域的上下文,当前场景下外层为模块顶层严格作用域,因此最终输出的this为undefined,完全丢失了Mongoose提供的文档实例上下文。
  • 按照Mongoose的内置机制,字段验证器的上下文默认指向当前正在校验的文档实例,只有使用普通函数(非箭头函数)定义验证器时,this才能正确拿到文档实例上挂载的会话访问方法。

正确实现流程

  1. 将字段的自定义验证器改写为普通异步函数,此时函数内部的this会自动绑定当前待校验的文档实例。
  2. 在验证器内部直接调用this.$session()方法,即可获取当前文档关联的Mongoose会话实例。
  3. 执行关联字段的存在性校验时,将拿到的会话绑定到查询链上,确保所有校验操作与文档写入处于同一个事务上下文内。

修正后的可运行示例代码

import mongoose from "mongoose";

async function run() {
  // 被关联的Account模型
  const accountSchema = new mongoose.Schema({
    name: { type: String, required: true }
  });
  const Account = mongoose.model("Account", accountSchema);

  const userSchema = new mongoose.Schema({
    accountId: {
      type: mongoose.Schema.Types.ObjectId,
      required: true,
      // 使用普通函数定义验证器,确保this正确绑定当前文档
      validate: async function (val) {
        // 通过文档实例获取关联的会话
        const currentSession = this.$session();
        // 基于会话执行关联对象存在性校验
        const validCount = await Account
          .findById(val)
          .session(currentSession)
          .countDocuments();
        // 校验不通过时抛出错误
        if (validCount === 0) {
          throw new Error("关联的账户对象不存在");
        }
      }
    }
  });
  const User = mongoose.model("User", userSchema);

  await mongoose.connect("mongodb://localhost:27017/mongoose_demo");

  // 事务操作示例
  const session = await mongoose.startSession();
  session.startTransaction();
  try {
    // 在同一事务内创建被关联的账户对象
    const [createdAccount] = await Account.create(
      [{ name: "测试业务账户" }],
      { session }
    );
    // 创建用户文档时绑定当前会话,保存时触发的验证器可正常获取会话
    const testUser = new User({ accountId: createdAccount._id });
    await testUser.save({ session });
    await session.commitTransaction();
  } catch (err) {
    await session.abortTransaction();
    throw err;
  } finally {
    session.endSession();
  }
}

run();

常见注意事项

  • 禁止使用箭头函数定义字段级自定义验证器,箭头函数的词法绑定机制会直接切断Mongoose的上下文注入逻辑,导致永远无法获取文档实例与会话信息。
  • 文档在初始化、保存操作时必须显式传入绑定的会话,否则this.$session()会返回空值,后续的校验查询会脱离事务隔离规则,出现校验逻辑与实际写入数据不一致的问题。
  • 所有关联校验的查询操作都需要通过.session(会话实例)的方法绑定上下文,否则查询不会读取当前事务内未提交的写入数据,导致明明已经在事务内创建的关联对象,校验时却提示不存在。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 16:15:04