[英]Using (and reusing) multiple mongoose database connections on express.js
I'm looking for the easiest & performant way to make a multitenant express.js app for managing projects. 我正在寻找最简单,最高效的方法来制作用于管理项目的多租户express.js应用程序。
Reading several blogs and articles, I figured out that, for my application, would be nice to have a database per tenant architecture. 阅读几篇博客和文章,我发现,对于我的应用程序,每个租户架构都有一个数据库会很好。
My first try has been to use subdomains to detect the tenant, and then map the subdomain to a mongodb database. 我的第一次尝试是使用子域来检测租户,然后将子域映射到mongodb数据库。
I came up with this express middlewares 我想出了这个快速的中间件
var mongoose = require('mongoose');
var debug = require('debug')('app:middleware:mongooseInstance');
var conns [];
function mongooseInstance (req, res, next) {
var sub = req.sub = req.subdomains[0] || 'app';
// if the connection is cached on the array, reuse it
if (conns[sub]) {
debug('reusing connection', sub, '...');
req.db = conns[sub];
} else {
debug('creating new connection to', sub, '...');
conns[sub] = mongoose.createConnection('mongodb://localhost:27017/' + sub);
req.db = conns[sub];
}
next();
}
module.exports = mongooseInstance;
Then I register the models inside another middleware: 然后我在另一个中间件中注册模型:
var fs = require('fs');
var debug = require('debug')('app:middleware:registerModels');
module.exports = registerModels;
var models = [];
var path = __dirname + '/../schemas';
function registerModels (req, res, next) {
if(models[req.sub]) {
debug('reusing models');
req.m = models[req.sub];
} else {
var instanceModels = [];
var schemas = fs.readdirSync(path);
debug('registering models');
schemas.forEach(function(schema) {
var model = schema.split('.').shift();
instanceModels[model] = req.db.model(model, require([path, schema].join('/')));
});
models[req.sub] = instanceModels;
req.m = models[req.sub];
}
next();
}
Then I can proceed normally as any other express.js app: 然后我可以像任何其他express.js应用程序一样正常进行:
var express = require('express');
var app = express();
var mongooseInstance = require('./lib/middleware/mongooseInstance');
var registerModels = require('./lib/middleware/registerModels');
app.use(mongooseInstance);
app.use(registerModels);
app.get('/', function(req, res, next) {
req.m.Project.find({},function(err, pets) {
if(err) {
next(err);
}
res.json({ count: pets.length, data: pets });
});
});
app.get('/create', function (req, res) {
var p = new req.m.Project({ name: 'Collin', description: 'Sad' });
p.save(function(err, pet) {
res.json(pet);
});
});
app.listen(8000);
The app is working fine, I don't have more than this right now, and I'd like to get some feedback before I go on, so my questions would be: 该应用程序工作正常,我现在没有更多,我想在继续之前得到一些反馈,所以我的问题是:
Is this approach is efficient? 这种方法有效吗? Take into account that a lot will be happening here, multiple tenants, several users each, I plan to setup webhooks in order to trigger actions on each instance, emails, etc...
考虑到这里将会发生很多事情,多个租户,每个都有几个用户,我计划设置webhooks以触发每个实例,电子邮件等的操作......
Are there any bottlenecks/pitfalls I'm missing? 我有什么瓶颈/缺陷吗? I'm trying to make this scalable from the start.
我试图从一开始就使这个可扩展。
What about the model registering? 模型注册怎么样? I didn't found any other way to accomplish this.
我没有找到任何其他方法来实现这一目标。
Thanks! 谢谢!
Is this approach is efficient?
这种方法有效吗? Are there any bottlenecks/pitfalls I'm missing?
我有什么瓶颈/缺陷吗?
This all seems generally correct to me 这一切似乎对我来说都是正确的
What about the model registering?
模型注册怎么样?
I agree with @narc88 that you don't need to register models in middleware. 我同意@ narc88你不需要在中间件中注册模型。
For lack of a better term, I would use a factory pattern. 由于缺乏更好的术语,我会使用工厂模式。 This "factory function" would take in your sub-domain, or however you decide to detect tenants, and return a
Models
object. 这个“工厂函数”会占用您的子域,或者您决定检测租户,并返回一个
Models
对象。 If a given middleware wants to use its available Models
you just do 如果给定的中间件想要使用其可用的
Models
那么您就是这样做的
var Models = require(/* path to your Model factory */);
...
// later on inside a route, or wherever
var models = Models(req.sub/* or req.tenant ?? */);
models.Project.find(...);
For an example "factory", excuse the copy/paste 有关“工厂”的示例,请原谅复制/粘贴
var mongoose = require('mongoose');
var fs = require('fs');
var debug = require('debug')('app:middleware:registerModels');
var models = [];
var conns = [];
var path = __dirname + '/../schemas';
function factory(tenant) {
// if the connection is cached on the array, reuse it
if (conns[tenant]) {
debug('reusing connection', tenant, '...');
} else {
debug('creating new connection to', tenant, '...');
conns[tenant] = mongoose.createConnection('mongodb://localhost:27017/' + tenant);
}
if(models[tenant]) {
debug('reusing models');
} else {
var instanceModels = [];
var schemas = fs.readdirSync(path);
debug('registering models');
schemas.forEach(function(schema) {
var model = schema.split('.').shift();
instanceModels[model] = conns[tenant].model(model, require([path, schema].join('/')));
});
models[tenant] = instanceModels;
}
return models[tenant];
}
module.exports = factory;
Aside from potential (albeit probably small) performance gain, I think it also has the advantage of: 除了潜在的(虽然可能很小)性能提升,我认为它还具有以下优势:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.