Mongoose动态模型,不能使用populate()

时间:2021-08-21 02:36:11

My CMS is written in Node.js + Express + Mongoose. It's a multisite CMS and each site has its own database. So I needed to make Mongoose to switch the connection at every HTTP request. I looked around for some solution, or someone who had my same condition, but without success. So this is my solution:

我的CMS是用Node编写的。js + Express + Mongoose。它是一个多站点的CMS,每个站点都有自己的数据库。所以我需要让Mongoose在每次HTTP请求时切换连接。我四处寻找解决办法,或者找一个和我条件一样但没有成功的人。这就是我的解决方案:

HTTP Request:

HTTP请求:

router.get('/site/pages', function (req, res) {
    pagesBiz.list(req.session, function(err, list) {
        //do stuff
    });
});

BIZ component (pagesBiz):

商业组件(pagesBiz):

module.exports = {
    list: function(session, callback) {
        Page(session.database).find(callback);
    }
}

Model (Page)

模型(页面)

var cached = {};
var getModel = function (database) {
    if(! cached[database]) {
        var conn = mongoose.createConnection('mongodb://localhost/' + database);
        cached[database] = conn.model('Page', pageSchema);
    }

    return cached[database];
}

module.exports = function(database) {
    return getModel(database);
}

So how does it works? When the user logs in a new user session is created and bound to the user via the session cookie (I use MongoStore + Express Session). The session contains the name of the database that is used to dynamically instantiate the Mongoose models.

那么它是如何工作的呢?当用户登录一个新的用户会话时,创建并通过会话cookie绑定到用户(我使用MongoStore + Express会话)。会话包含用于动态实例化Mongoose模型的数据库的名称。

It works perfectly, users of different sites read from their own databases without the risk of "collisions", on the other side I have to pass the session (or the database name) around the functions, but I guess this is how Node.js works in a multithreaded context.

它工作得很好,不同站点的用户可以从自己的数据库中读取数据,而不存在“冲突”的风险,另一方面,我必须在函数周围传递会话(或数据库名称),但我猜这就是Node。js在多线程上下文中工作。

The only problem is when I use the populate method(), I get this error:

唯一的问题是当我使用populate方法()时,我得到这个错误:

f:\www\rudsjs\node_modules\mongoose\lib\connection.js:625 throw new MongooseError.MissingSchemaError(name); ^ MissingSchemaError: Schema hasn't been registered for model "User". Use mongoose.model(name, schema) at NativeConnection.Connection.model (f:\www\rudsjs\node_modules\mongoose\lib\connection.js:625:11) at populate (f:\www\rudsjs\node_modules\mongoose\lib\model.js:2136:24) at Function.Model.populate (f:\www\rudsjs\node_modules\mongoose\lib\model.js:2101:5) at Object.cb (f:\www\rudsjs\node_modules\mongoose\lib\query.js:1159:16) at Object._onImmediate (f:\www\rudsjs\node_modules\mongoose\node_modules\mquery\lib\utils.js:137:16) at processImmediate [as _immediateCallback] (timers.js:336:15)

f:\ www \ rudsjs \ node_modules \猫鼬\ lib \连接。js:625把新MongooseError.MissingSchemaError(名称);^ MissingSchemaError:模式尚未注册模型“用户”。使用猫鼬。在NativeConnection.Connection模型(名称、模式)。model (f:\www\rudsjs\node_modules\mongoose\lib\connection.js:625:11)在功能型。模型中。填充(f:\ www \ rudsjs \ node_modules \猫鼬\ lib \ model.js:2101:5)对象。cb(f:\ www \ rudsjs \ node_modules \猫鼬\ lib \ query.js:1159:16)对象。直接(f:\www\rudsjs\node_modules\ node_modules\ node_modules\mquery\lib\utils.js:137:16)在processim[即日起](timers.js:336:15)。

Process finished with exit code 8

进程完成与退出代码8

I tried to preload the model before the populate() call using this:

我尝试在填充()调用之前预加载模型:

User(session.database);

用户(session.database);

but the problem seems to be related to the way Mongoose caches the models (that is not mine), I looked at connection.js

但问题似乎与Mongoose缓存模型的方式有关(那不是我的),我查看了connection.js

  model = this.base.models[name];

  if (!model) {
    throw new MongooseError.MissingSchemaError(name);
  }

so I'd need a way to insert my model inside this.base.models. Do you have any idea? Do you especially have a better solution to implement a multi-site/multi-database environment?

我需要一种方法将模型插入到。base。models中。你知道吗?您是否有更好的解决方案来实现多站点/多数据库环境?

1 个解决方案

#1


0  

I found a solution. I was caching the models and not the connections, so I was spawning a new Mongoose connection for each model, that's why Mongoose wasn't able to load other models using populate().

我找到了一个解决方案。我正在缓存模型而不是连接,所以我正在为每个模型生成一个新的Mongoose连接,这就是为什么Mongoose不能使用populate()加载其他模型。

My solution is: use a global Cache object that stores the connections that will be used to build all the models.

我的解决方案是:使用一个全局缓存对象,它存储用于构建所有模型的连接。

Cache global object

缓存全局对象

module.exports = {
Cache: {
        database: {}
    }
}

Model (Page)

模型(页面)

module.exports = function(session) {
    if(! Cache.database[session.database]) {
        debug("Create connection to " + session.database);
        var conn = mongoose.createConnection('mongodb://localhost/' + session.database);
        Cache.database[session.database] = conn;
    }

    debug("[rud] " + session.database + " model created");
    return Cache.database[session.database].model('Page', pageSchema);
}

As you can see all models now will share the same connection stored in Cache.database[session.database]

正如您现在看到的,所有模型都将共享存储在Cache.database[session.database]中的相同连接

#1


0  

I found a solution. I was caching the models and not the connections, so I was spawning a new Mongoose connection for each model, that's why Mongoose wasn't able to load other models using populate().

我找到了一个解决方案。我正在缓存模型而不是连接,所以我正在为每个模型生成一个新的Mongoose连接,这就是为什么Mongoose不能使用populate()加载其他模型。

My solution is: use a global Cache object that stores the connections that will be used to build all the models.

我的解决方案是:使用一个全局缓存对象,它存储用于构建所有模型的连接。

Cache global object

缓存全局对象

module.exports = {
Cache: {
        database: {}
    }
}

Model (Page)

模型(页面)

module.exports = function(session) {
    if(! Cache.database[session.database]) {
        debug("Create connection to " + session.database);
        var conn = mongoose.createConnection('mongodb://localhost/' + session.database);
        Cache.database[session.database] = conn;
    }

    debug("[rud] " + session.database + " model created");
    return Cache.database[session.database].model('Page', pageSchema);
}

As you can see all models now will share the same connection stored in Cache.database[session.database]

正如您现在看到的,所有模型都将共享存储在Cache.database[session.database]中的相同连接