Javascript 关于模型创建的Mongoose无限循环 背景
我有关于调查的猫鼬模式,需要检查调查是否属于另一个集合中的一组国家 代码 为了检查这一点,我有一个surveySchema、一个countrySchema和一个创建模型并连接到DB的文件 为了检查调查是否属于有效的国家/地区,我在surveySchema中使用如下内容: surveySchema.js:Javascript 关于模型创建的Mongoose无限循环 背景,javascript,node.js,mongodb,mongoose,Javascript,Node.js,Mongodb,Mongoose,我有关于调查的猫鼬模式,需要检查调查是否属于另一个集合中的一组国家 代码 为了检查这一点,我有一个surveySchema、一个countrySchema和一个创建模型并连接到DB的文件 为了检查调查是否属于有效的国家/地区,我在surveySchema中使用如下内容: surveySchema.js: "use strict"; const mongoose = require("mongoose"); const surveySchema = { subject: { type:
"use strict";
const mongoose = require("mongoose");
const surveySchema = {
subject: { type: String, required: true },
country: {
type: String,
validate: {
validator: {
isAsync: true,
validator: async function(val, callback) {
const {
Country
} = require("./models.js").getModels();
const countriesNum = await Country.find({"isoCodes.alpha2": val}).count();
callback(countriesNum === 1);
}
},
message: "The country {VALUE} is not available in the DB at the moment."
}
}
};
module.exports = new mongoose.Schema(surveySchema);
module.exports.surveySchema = surveySchema;
"use strict";
const mongoose = require("mongoose");
const countrySchema = {
name: { type: String, required: true },
isoCodes:{
alpha2: { type: String, required: true }
}
}
};
module.exports = new mongoose.Schema(countrySchema);
module.exports.countrySchema = countrySchema;
"use strict";
const mongoose = require("mongoose");
const fs = require("fs");
const DB_CONFIG = "./config/dbConfig.json";
/**
* Module responsible for initializing the Models. Should be a Singleton.
*/
module.exports = (function() {
let models;
const initialize = () => {
//Connect to DB
const {
dbConnectionURL
} = JSON.parse(fs.readFileSync(DB_CONFIG, "utf8"));
mongoose.connect(dbConnectionURL);
mongoose.Promise = global.Promise;
//Build Models Object
models = {
Country: mongoose.model('Country', require("./countrySchema.js")),
Survey: mongoose.model('Survey', require("./surveySchema.js"))
};
};
const getModels = () => {
if (models === undefined)
initialize();
return models;
};
return Object.freeze({
getModels
});
}());
countrySchema.js:
"use strict";
const mongoose = require("mongoose");
const surveySchema = {
subject: { type: String, required: true },
country: {
type: String,
validate: {
validator: {
isAsync: true,
validator: async function(val, callback) {
const {
Country
} = require("./models.js").getModels();
const countriesNum = await Country.find({"isoCodes.alpha2": val}).count();
callback(countriesNum === 1);
}
},
message: "The country {VALUE} is not available in the DB at the moment."
}
}
};
module.exports = new mongoose.Schema(surveySchema);
module.exports.surveySchema = surveySchema;
"use strict";
const mongoose = require("mongoose");
const countrySchema = {
name: { type: String, required: true },
isoCodes:{
alpha2: { type: String, required: true }
}
}
};
module.exports = new mongoose.Schema(countrySchema);
module.exports.countrySchema = countrySchema;
"use strict";
const mongoose = require("mongoose");
const fs = require("fs");
const DB_CONFIG = "./config/dbConfig.json";
/**
* Module responsible for initializing the Models. Should be a Singleton.
*/
module.exports = (function() {
let models;
const initialize = () => {
//Connect to DB
const {
dbConnectionURL
} = JSON.parse(fs.readFileSync(DB_CONFIG, "utf8"));
mongoose.connect(dbConnectionURL);
mongoose.Promise = global.Promise;
//Build Models Object
models = {
Country: mongoose.model('Country', require("./countrySchema.js")),
Survey: mongoose.model('Survey', require("./surveySchema.js"))
};
};
const getModels = () => {
if (models === undefined)
initialize();
return models;
};
return Object.freeze({
getModels
});
}());
models.js:
"use strict";
const mongoose = require("mongoose");
const surveySchema = {
subject: { type: String, required: true },
country: {
type: String,
validate: {
validator: {
isAsync: true,
validator: async function(val, callback) {
const {
Country
} = require("./models.js").getModels();
const countriesNum = await Country.find({"isoCodes.alpha2": val}).count();
callback(countriesNum === 1);
}
},
message: "The country {VALUE} is not available in the DB at the moment."
}
}
};
module.exports = new mongoose.Schema(surveySchema);
module.exports.surveySchema = surveySchema;
"use strict";
const mongoose = require("mongoose");
const countrySchema = {
name: { type: String, required: true },
isoCodes:{
alpha2: { type: String, required: true }
}
}
};
module.exports = new mongoose.Schema(countrySchema);
module.exports.countrySchema = countrySchema;
"use strict";
const mongoose = require("mongoose");
const fs = require("fs");
const DB_CONFIG = "./config/dbConfig.json";
/**
* Module responsible for initializing the Models. Should be a Singleton.
*/
module.exports = (function() {
let models;
const initialize = () => {
//Connect to DB
const {
dbConnectionURL
} = JSON.parse(fs.readFileSync(DB_CONFIG, "utf8"));
mongoose.connect(dbConnectionURL);
mongoose.Promise = global.Promise;
//Build Models Object
models = {
Country: mongoose.model('Country', require("./countrySchema.js")),
Survey: mongoose.model('Survey', require("./surveySchema.js"))
};
};
const getModels = () => {
if (models === undefined)
initialize();
return models;
};
return Object.freeze({
getModels
});
}());
这里的想法是,我在其他地方也使用了models.js文件。因为这个文件还负责连接到数据库,所以我决定将其设置为单例。这样,我应该只连接一次,所有进一步的请求将始终返回相同的模型,这将是理想的
问题
这里的问题是,我有一个循环依赖,导致:
RangeError: Maximum call stack size exceeded at exports.isMongooseObject (/home/ubuntu/workspace/server/node_modules/mongoose/lib/utils.js:537:12)
导致此错误的代码流是:
getModels()
检查models
是否未定义并运行initialize()
initialize()
尝试创建模型李>
Survey:mongoose.model('Survey',require(“./surveySchema.js”)
会运行到验证程序
函数中,该函数再次需要models.js
正如评论中所说,我认为您对如何使用models.js模块感到有点困惑。我认为这就是正在发生的事情: 您正在从models.js导出单个函数: models.js
module.exports = function() { ... };
const models = require("./models.js");
module.exports = (function() {
// codez here
return Object.freeze({
getModels
});
})(); // immediately invoke the function.
因此,当您需要它时,您只需获得单一功能:
surveySchema.js
module.exports = function() { ... };
const models = require("./models.js");
module.exports = (function() {
// codez here
return Object.freeze({
getModels
});
})(); // immediately invoke the function.
型号
现在是一项功能。这意味着每次调用它时,您都会运行models.js中的代码,并创建一个新变量let models代码>,以及新函数initialize()
和getModels()
您可以将let models
从匿名函数移到全局范围内,这可能会修复它,但就我的钱而言,您只想在models.js中运行匿名函数一次,因此我会将模块的导出设置为其结果:
models.js
module.exports = function() { ... };
const models = require("./models.js");
module.exports = (function() {
// codez here
return Object.freeze({
getModels
});
})(); // immediately invoke the function.
使用它:
// models is now the frozen object returned
const { Survey } = models.getModels();
至于验证选项,如果正常异步验证不能使用中所述的串行或并行机制为您添加自己的中间件验证代码,那么您没有理由不能添加自己的中间件验证代码
评论后更新
您指出的第二个问题是,在第一次执行getModels()->initialize()
期间,您调用require('./surveySchema.js')
,但这调用了getModels()
,它仍在被调用的过程中,尚未初始化模型,因此重新输入initialize()
我认为您试图实现的是很好的(调查模式取决于客户模型),因为您仍然可以绘制没有任何循环依赖关系的对象图,而您实现它的方式就是这样的。我认为处理这个问题的最简单方法实际上是保留循环引用,但推迟调用surveySchema.js中的getModels()
:
"use strict";
const mongoose = require("mongoose");
const models = require("./models.js");
const surveySchema = {
subject: { type: String, required: true },
country: {
type: String,
validate: {
validator: {
isAsync: true,
validator: async function(val, callback) {
// !! moved from the global scope to here, where we actually use it
const {
Country
} = models.getModels();
const countries = await Country.find({"isoCodes.alpha2": val});
callback(countries.length === 1);
}
},
message: "The country {VALUE} is not available in the DB at the moment."
}
}
};
module.exports = new mongoose.Schema(surveySchema);
module.exports.surveySchema = surveySchema;
不过,一种更简洁且可能更具扩展性的方法可能是将连接代码与模型代码分开,因为这是一个完全不同的概念
更多评论后更新#2
您看到的无限堆栈是因为您没有正确使用API。你有:
const surveySchema = {
country: {
validate: {
validator: {
isAsync: true,
validator: async function(val, callback) {...}
},
},
...
}
};
你应该:
const surveySchema = {
country: {
validate: {
isAsync: true,
validator: async function(val, callback) {...}
},
...
}
};
根据。为什么您认为异步验证不是一个好方法?而且您的单例不起作用,因为每次调用models()
,let models代码>运行。所以它总是没有定义的。如果你选择让模型
在模块之外。exports
可能会解决这个问题。我认为异步验证可能不是这里的答案,因为我需要包含来自另一个模式的模型。至于let models
语句,将其置于函数之外也不能解决问题。也许我不够清楚。作为一个在这里寻求帮助的人,我自己完全理解并测试给我的每一个建议。当我说你的建议不起作用时,我的意思是我已经测试了它,它不起作用=(我已经更新了我的答案以反映你的建议,但正如我所说的,它仍然不起作用,因为变量models
始终是未定义的。你确定代码到达models={…
第一次调用models.js,第二次调用.getModels()
之前,在models.js中的行?很好。因此,代码流运行models.js
来创建模型。但是,在models.js
中,我尝试创建调查模式,该模式调用const{Country}=models.getModels();
,它又尝试再次运行models.js
文件。但是,该文件仍在尝试从第一次开始创建模型,因此在第二次运行中,变量models
显然是未定义的
。我在这里几乎陷入了一个循环。这是一个我没有解决的架构问题解决方案还没有…也许我应该更新我的问题?我不知道如何解决这个问题…好吧,如果我按照你的建议去做,我会得到一个超过最大调用堆栈大小的错误。甚至当我在验证器函数中定义const{Country}…
时也会发生这种情况。这意味着我可能有一个无限递归b