模型创建时的猫鼬无限循环



Background

我有关于调查的猫鼬模式,需要检查调查是否属于另一个集合中的一组国家/地区。

法典

为了检查这一点,我有一个调查模式、一个国家模式和一个文件,我在其中创建模型并连接到数据库。

为了检查调查是否属于有效国家/地区,我在 surveySchema 中使用了 Mongoose 异步验证器,如下所示:

调查架构.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;

国家架构.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;

型号.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文件。由于此文件还负责连接到数据库,因此我决定将其设置为单例。这样,我应该只连接一次,所有进一步的请求将始终返回相同的模型,这将是理想的。

问题

这里的问题是我有一个循环依赖,导致:

RangeError: Maximum call stack size exceeded at exports.isMongooseObject (/home/ubuntu/workspace/server/node_modules/mongoose/lib/utils.js:537:12)

导致此错误的代码流是:

  1. 代码运行 getModels()'
  2. getModels()检查models是否未定义并运行initialize()
  3. initialize()尝试创建模型。
  4. 创建调查模型时Survey: mongoose.model('Survey', require("./surveySchema.js"))它会遇到validator函数,这再次需要models.js
  5. 无限循环开始

问题

  1. 有没有其他方法可以在不进行异步验证的情况下检查调查的国家/地区是否是该县集合的一部分?
  2. 如何构建/更改我的代码以免发生这种情况?

正如评论中所说,我认为您对如何使用模型.js模块有点困惑。我认为这就是正在发生的事情:

您正在从模型中导出单个函数.js:

模型.js

module.exports = function() { ... };

因此,当您需要它时,您只需获得单个功能:

调查架构.js

const models = require("./models.js");

models现在是一个函数。这意味着每次调用它时,您都会运行模型中的代码.js并创建一个新的变量let models;,以及initialize()getModels()的新功能。

您可以将let models从匿名函数移到全局范围内,这可能会修复它,但为了我的钱,您只想在模型中运行匿名函数.js一次,所以我会立即调用它并将模块的导出设置为其结果:

模型.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()仍在被调用的过程中并且尚未初始化models,因此重新输入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) {...}
},
...
}
};

根据文档。

最新更新