模型创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是:

  1. 代码运行getModels()`
  2. getModels()检查models未定义并运行initialize()
  3. initialize()尝试创build模型。
  4. 当创build测量模型Survey: mongoose.model('Survey', require("./surveySchema.js"))它会运行到validator函数中,这又需要models.js
  5. 无限循环开始

问题

  1. 有没有其他方法可以检查一个调查国家是不是县收集的一部分,而不进行asynchronousvalidation?
  2. 我怎样才能构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) {...} }, ... } }; 

根据文档 。