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]中的相同连接