模型创build的mongoose无限循环
背景
我有关于调查的Mongoose Schema,需要检查调查是否属于另一个集合中的一组国家。
码
要检查这一点,我有一个surveySchema,一个countrySchema和一个文件,我创build模型并连接到数据库。
要执行调查属于有效国家/地区的检查,我在surveySchema中使用了Mongooseasynchronousvalidation器 ,如下所示:
surveySchema.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;
countrySchema.js:
"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;
models.js:
"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文件。 因为这个文件也负责连接到数据库,所以我决定把它变成一个Singleton。 这样,我只应该连接一次,所有进一步的请求将始终返回相同的模型,这将是理想的。
问题
这里的问题是,我有一个循环依赖,导致:
RangeError: Maximum call stack size exceeded at exports.isMongooseObject (/home/ubuntu/workspace/server/node_modules/mongoose/lib/utils.js:537:12)
…
导致此错误的代码stream是:
- 代码运行getModels()`
-
getModels()
检查models
未定义并运行initialize()
-
initialize()
尝试创build模型。 - 当创build测量模型
Survey: mongoose.model('Survey', require("./surveySchema.js"))
它会运行到validator
函数中,这又需要models.js
- 无限循环开始
问题
- 有没有其他方法可以检查一个调查国家是不是县收集的一部分,而不进行asynchronousvalidation?
- 我怎样才能构build/更改我的代码,所以这不会发生?
正如在评论中所说,我认为你对你如何使用你的models.js模块有点困惑。 我认为这是发生的事情:
您正在从models.js中导出单个函数:
models.js
module.exports = function() { ... };
因此,当你需要的时候,你可以得到这个单一的function:
surveySchema.js
const models = require("./models.js");
models
现在是一个function。 这意味着每次调用它时,都会运行models.js中的代码并创build一个新variableslet models;
,还有新的函数initialize()
和getModels()
。
你可以将let models
移出匿名函数进入全局范围,这可能会解决这个问题,但是为了我的钱,你只需要在models.js中运行一次匿名函数,所以我会立即调用它,并设置出口该模块对其结果:
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();
至于validation的选项,如果正常的asynchronousvalidation不使用文档中描述的串行或并行机制为您添加自己的中间件validation代码,那没有任何理由。
在评论之后更新
您指出的第二个问题是,在第一次执行getModels() -> initialize()
您会调用require('./surveySchema.js')
,但这会调用仍在调用过程中的getModels()
尚未初始化models
,所以initialize()
被重新input。
我认为你试图达到的目标是好的(调查模式取决于客户模型 ),因为你仍然可以绘制一个没有任何循环依赖的对象图,这只是你实现它的方式,你已经结束了一。 处理这个问题的最简单的方法是实际上保留循环引用,但推迟调用surveySchema.js
getModels()
surveySchema.js
:
"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) {...} }, ... } };
根据文档 。