使用Model.collection.name定义Mongoose双向引用模型的循环依赖问题
解决Mongoose循环引用中动态集合名的问题
你遇到的循环依赖问题,本质是Schema初始化阶段两个Model还未完成编译,互相引用对方的collection.name会导致引用报错。这里有几个不用硬编码集合名的解决思路:
方案1:延迟设置引用关系
先创建不带ref的Schema,等两个Model都编译完成后,再动态修改Schema的引用配置:
// 先定义基础Schema const ASchema = new mongoose.Schema({ someStuff: String, children: [{ type: mongoose.Schema.Types.ObjectId }] }); const BSchema = new mongoose.Schema({ someOtherStuff: String, parent: { type: mongoose.Schema.Types.ObjectId } }); // 编译Model const ModelA = mongoose.model('A', ASchema); const ModelB = mongoose.model('B', BSchema); // 动态设置ref ASchema.path('children').options.ref = ModelB.collection.name; BSchema.path('parent').options.ref = ModelA.collection.name;
方案2:使用函数式引用
Mongoose允许ref接收一个函数,函数会在需要解析引用时才执行,避开初始化阶段的循环问题:
// 先声明Model变量(提前占位) let ModelA, ModelB; const ASchema = new mongoose.Schema({ someStuff: String, children: [{ type: mongoose.Schema.Types.ObjectId, ref: () => ModelB.collection.name }] }); const BSchema = new mongoose.Schema({ someOtherStuff: String, parent: { type: mongoose.Schema.Types.ObjectId, ref: () => ModelA.collection.name } }); // 编译Model ModelA = mongoose.model('A', ASchema); ModelB = mongoose.model('B', BSchema);
方案3:抽离集合名称常量
把集合名单独放在一个常量文件里,两个Schema直接引用常量,既避免硬编码,也不会产生循环依赖:
// constants/collectionNames.js module.exports = { COLLECTION_A: 'A', COLLECTION_B: 'B' }; // models/A.js const { COLLECTION_B } = require('../constants/collectionNames'); const ASchema = new mongoose.Schema({ someStuff: String, children: [{ type: mongoose.Schema.Types.ObjectId, ref: COLLECTION_B }] }); module.exports = mongoose.model('A', ASchema); // models/B.js const { COLLECTION_A } = require('../constants/collectionNames'); const BSchema = new mongoose.Schema({ someOtherStuff: String, parent: { type: mongoose.Schema.Types.ObjectId, ref: COLLECTION_A } }); module.exports = mongoose.model('B', BSchema);
这三个方案都能避免硬编码集合名,同时解决循环依赖问题,你可以根据项目结构选择合适的方案。
内容的提问来源于stack exchange,提问作者Jose Arrillaga
相关产品推荐
相关产品推荐

