ric*_*res 3 middleware mongoose multi-tenant node.js express
我正在寻找最简单,最高效的方法来制作用于管理项目的多租户express.js应用程序.
阅读几篇博客和文章,我发现,对于我的应用程序,每个租户架构都有一个数据库会很好.
我的第一次尝试是使用子域来检测租户,然后将子域映射到mongodb数据库.
我想出了这个快速的中间件
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;
Run Code Online (Sandbox Code Playgroud)
然后我在另一个中间件中注册模型:
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();
}
Run Code Online (Sandbox Code Playgroud)
然后我可以像任何其他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);
Run Code Online (Sandbox Code Playgroud)
该应用程序工作正常,我现在没有更多,我想在继续之前得到一些反馈,所以我的问题是:
这种方法有效吗?考虑到这里将会发生很多事情,多个租户,每个都有几个用户,我计划设置webhooks以触发每个实例,电子邮件等的操作......
我有什么瓶颈/缺陷吗?我试图从一开始就使这个可扩展.
模型注册怎么样?我没有找到任何其他方法来实现这一目标.
谢谢!
这种方法有效吗?我有什么瓶颈/缺陷吗?
这一切似乎对我来说都是正确的
模型注册怎么样?
我同意@ narc88你不需要在中间件中注册模型.
由于缺乏更好的术语,我会使用工厂模式.这个"工厂功能"会占用您的子域,或者您决定检测租户,并返回一个Models对象.如果给定的中间件想要使用它可用,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(...);
Run Code Online (Sandbox Code Playgroud)
有关"工厂"的示例,请原谅复制/粘贴
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;
Run Code Online (Sandbox Code Playgroud)
除了潜在的(虽然可能很小)性能提升,我认为它还具有以下优势:
| 归档时间: |
|
| 查看次数: |
1744 次 |
| 最近记录: |