Mongoose报错:User.findById is not a function,关联模型同步删除问题
解决Mongoose循环依赖导致的
User.findById is not a function错误 你遇到的这个问题核心是模型循环依赖:你的User模型导入了Leave,同时Leave模型又导入了User。Node.js模块加载机制下,这种互相引用会导致其中一个模型在加载时还没完成导出,所以你拿到的User对象是未完全初始化的,自然没有findById这类方法。
另外,你的pre('remove')中间件还有异步操作未正确等待的问题,这会导致数据同步不彻底,我一起帮你修复:
步骤1:修复循环依赖问题
在Leave模型中,不要通过require('../models/user')导入User,而是直接使用Mongoose已经注册的模型:mongoose.model('User')。这样就绕开了模块循环引用的问题。
步骤2:修复异步操作的等待逻辑
pre('remove')中间件里的数据库操作都是异步的,直接调用next()会在操作完成前就执行后续流程,必须等待异步操作完成后再调用next(),可以用async/await让代码更清晰。
修改后的Leave模型代码
const mongoose = require('mongoose'); const Schema = mongoose.Schema; // 移除循环引用的require,改用mongoose.model获取已注册的模型 const { ObjectID } = require('mongodb'); var schema = new Schema({ userId: { type: Schema.Types.ObjectId, ref: 'User' }, status: { type: String, required: true }, start: { type: String, required: true }, end: { type: String, required: true }, type: { type: String, required: true } }); // 改用async/await处理异步操作 schema.pre('remove', async function(next) { try { const leave = this; // 获取User模型 const User = mongoose.model('User'); const user = await User.findById(new ObjectID(leave.userId)); if (user) { user.filedLeaves.pull(leave._id); await user.save(); } next(); } catch (err) { next(err); // 传递错误给错误处理中间件 } }); module.exports = mongoose.model('Leave', schema);
修改后的User模型代码
同样修复循环依赖和异步等待问题:
const mongoose = require('mongoose'); const Schema = mongoose.Schema; const muv = require('mongoose-unique-validator'); // 移除循环引用的require,改用mongoose.model获取已注册的Leave模型 const { ObjectID } = require('mongodb'); var schema = new Schema({ fullName: { type: String, required: true, unique: true }, leaveCredits: { type: Number }, filedLeaves: [{ type: Schema.Types.ObjectId, ref: 'Leave' }] }, { usePushEach: true }); schema.plugin(muv); // 改用async/await处理批量删除Leave的异步操作 schema.pre('remove', async function(next) { try { const user = this; const Leave = mongoose.model('Leave'); // 用Promise.all等待所有删除操作完成 await Promise.all(user.filedLeaves.map(item => Leave.findByIdAndRemove(new ObjectID(item)) )); next(); } catch (err) { next(err); } }); module.exports = mongoose.model('User', schema);
额外说明
- 为什么
mongoose.model('User')能生效?因为当你调用mongoose.model('User', schema)导出模型时,Mongoose会把这个模型注册到全局的模型缓存里,后续通过mongoose.model('User')就能直接获取到完整的模型对象,不管模块加载顺序如何。 - 使用
async/await和Promise.all能确保所有异步操作完成后再执行后续逻辑,避免数据不同步的问题,同时也让错误处理更统一。
内容的提问来源于stack exchange,提问作者Nar
相关产品推荐
相关产品推荐

