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

Jest使用MongoMemoryServer/mongoose时无法读取Schema _id报错

问题根因

报错TypeError: Cannot read properties of null (reading 'ObjectId')的核心原因是测试执行阶段mongoose连接实例的db属性尚未初始化,值为null,你在createJWT方法中大概率写了从mongoose.connection.db上解构读取ObjectId的逻辑。
生产环境下服务启动流程会严格等待mongoose连接完全就绪后才开始处理业务请求,因此不会触发该问题;但Jest测试中如果没有完整等待MongoMemoryServer启动、mongoose连接建立完成就执行模型操作,就会命中这个null引用错误,这和你创建用户时传不传_id参数没有关系——报错点根本不在实例字段读取上,而在方法内部依赖的ObjectId对象来源为空。

修复步骤
  • 补全beforeAll生命周期的异步等待逻辑,强制指定MongoMemoryServer的二进制版本和生产环境对齐,避免版本兼容问题
    正确的测试初始化代码参考:
    const { MongoMemoryServer } = require('mongodb-memory-server');
    const mongoose = require('mongoose');
    const User = require('./User');
    
    let mongoServer;
    beforeAll(async () => {
      // 等待内存Mongo实例启动,指定和生产一致的5.0.7版本,避免默认拉取最新版MongoDB带来的驱动兼容问题
      mongoServer = await MongoMemoryServer.create({
        binary: { version: '5.0.7' }
      });
      const mongoUri = mongoServer.getUri();
      // 等待mongoose连接完全建立,禁止省略await
      await mongoose.connect(mongoUri);
      // 增加连接状态校验,确保连接就绪后再跑用例:1代表已连接
      if (mongoose.connection.readyState !== 1) {
        throw new Error('mongoose connect failed before test run');
      }
    });
    
    // 测试结束后清理连接和实例,避免测试进程挂死
    afterAll(async () => {
      await mongoose.disconnect();
      await mongoServer.stop();
    });
    
  • 修正createJWT方法中的ObjectId引用方式,不要从连接实例上读取ObjectId,彻底移除对连接初始化状态的依赖
    错误写法(触发报错的根源):
    // 连接未就绪时mongoose.connection.db值为null,解构时直接抛出你遇到的错误
    const { ObjectId } = mongoose.connection.db;
    userSchema.methods.createJWT = function () {
      // 业务逻辑中用到了上述ObjectId做类型校验
      return jwt.sign({ userId: this._id }, process.env.JWT_SECRET);
    };
    
    正确写法:
    // 直接从mongoose顶层Types对象上取ObjectId,不需要依赖数据库连接状态
    const { ObjectId } = mongoose.Types;
    userSchema.methods.createJWT = function () {
      // 如果只是读取实例的_id生成token,根本不需要额外引入ObjectId,直接读取this._id即可
      return jwt.sign(
        { userId: this._id },
        process.env.JWT_SECRET,
        { expiresIn: process.env.JWT_EXPIRES_IN }
      );
    };
    
  • 处理Jest模块缓存导致的模型绑定异常:如果测试中存在多次引入模型、重复连接的逻辑,在beforeEach中清理已注册的模型,避免拿到未绑定有效连接的模型副本
    beforeEach(() => {
      Object.keys(mongoose.models).forEach(modelName => {
        delete mongoose.models[modelName];
      });
      // 清理后再重新引入User模型即可
    });
    
验证标准

修复完成后,先单独运行创建用户的用例,确认三点即可解决问题:

  1. beforeAll执行完成后,mongoose连接状态为1(已连接)
  2. User.create返回的用户实例可以直接读取到_id字段值
  3. 调用实例的createJWT方法时不再抛出null引用错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 02:42:28