模型创建的猫鼬无限循环

时间:2017-04-08 09:12:22

标签: javascript node.js mongodb mongoose

背景

我有关于调查的Mongoose Schema,需要检查调查是否属于另一个集合中的一组国家。

代码

要检查这一点,我有一个surveySchema,countrySchema和一个文件,我在其中创建模型并连接到数据库。

要执行调查属于有效国家/地区的检查,我在surveySchema中使用Mongoose async validators,如下所示:

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)

...

导致此错误的代码流程为:

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

    1. 在没有进行异步验证的情况下,还有其他方法可以检查调查的国家/地区是否属于该县的收藏品吗?
    2. 如何构建/更改我的代码,以免发生这种情况?

1 个答案:

答案 0 :(得分:1)

如评论中所述,我认为您对如何使用models.js模块感到有些困惑。我认为这就是发生的事情:

您正在从models.js导出单个函数:

<强> models.js

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

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

<强> surveySchema.js

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

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

你可以将let models移出匿名函数进入可能修复它的全局范围,但是为了我的钱,你只想在models.js中运行一次匿名函数,所以我会{{ 3}}并将模块的导出设置为其结果:

<强> 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();

至于验证的选项,如果正常的异步验证没有为您使用串行或并行机制,您没有理由不添加自己的中间件验证代码,如invoke it immediately

评论后更新

您指出的第二个问题是,在第一次执行getModels() -> initialize()时,您调用了require('./surveySchema.js'),但这会调用getModels(),而models仍然处于被调用过程中并且还没有被调用; t尚未初始化initialize(),因此重新输入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; 的点:

const surveySchema = {
    country: {
        validate: {
            validator: {
                isAsync: true,
                validator: async function(val, callback) {...}
            },
        },
        ...
    }
};
但是,更简洁,可能更具可扩展性的方法可能是将连接代码与模型代码分开,因为它完全是一个不同的概念。

更多评论后更新#2

您看到的无限堆栈是因为您没有正确使用API​​。你有:

const surveySchema = {
    country: {
        validate: {
            isAsync: true,
            validator: async function(val, callback) {...}
        },
        ...
    }
};

你应该:

char c = i + 'A';
index = hashFunction(&c) % size;

根据the docs

相关问题