我的情况是:
我创建了一个中间件,可以确定客户端是基于子域,然后从通用数据库检索客户端的数据库连接信息.我不知道如何为这个客户端建立一个连接对象,以便能够在我的控制器中使用.我应该在中间件还是控制器中这样做?如果它在模型中,我如何传递连接字符串和参数(我可以使用会话,但我不知道如何从模型中访问会话).
我如何执行以下操作?
>组织:动态地为客户端创建数据库连接?
>将连接参数注入控制器或型号(连接定义)
>动态连接完成后,如何在全局访问该客户端?
这是我的中间件的一个例子,我想创建一个我想要动态(传递客户端的连接信息)的一个mongoose连接:
function clientlistener() { return function (req,res,next) { console.dir('look at my sub domain ' + req.subdomains[0]); // console.log(req.session.Client.name); if (req.session.Client && req.session.Client.name === req.subdomains[0]) { var options = session.Client.options; var url = session.Client.url var conn = mongoose.createConnection(url,options); next(); } } }
如何从控制器内部访问此连接对象?还是从模特儿?
谢谢.
解决方法
此示例描述了每个客户端都有自己的数据库的多租户结构.
就像我说的,可能会有一个更好的方法来做,但是因为我没有得到帮助,这是我的解决方案.
所以这里是这个解决方案的目标:
>每个客户端都由子域标识,例如client1.application.com,
>应用程序检查子域是否有效,
>应用程序查找并从主数据库获取连接信息(数据库URL,凭据等)
>应用程序连接到客户端数据库(几乎交给客户端),
>应用程序采取措施确保完整性和资源管理(例如,为同一客户端的成员使用相同的数据库连接,而不是进行新的连接).
这是代码
在你的app.js文件中
app.use(clientListener()); // checks and identify valid clients app.use(setclientdb());// sets db for valid clients
我创造了两个工具:
> clientListener – 识别客户端连接,
> setclientdb – 在客户端被识别后,从主数据库获取客户端详细信息,然后建立与客户端数据库的连接.
clientListener中间件
通过从请求对象中检查子域来检查客户端是谁.我做了一堆检查,以确保客户端是有效的(我知道代码是凌乱的,可以做得更干净).确保客户端有效后,我将客户端信息存储在会话中.我还检查,如果客户端信息已经存储在会话中,则不需要再次查询数据库.我们只需要确保请求子域名与已存储在会话中的请求子域名相匹配.
var Clients = require('../models/clients'); var basedomain = dbConfig.baseDomain; var allowedSubs = {'admin':true,'www':true }; allowedSubs[basedomain] = true; function clientlistener() { return function(req,next) { //console.dir('look at my sub domain ' + req.subdomains[0]); // console.log(req.session.Client.name); if( req.subdomains[0] in allowedSubs || typeof req.subdomains[0] === 'undefined' || req.session.Client && req.session.Client.name === req.subdomains[0] ){ //console.dir('look at the sub domain ' + req.subdomains[0]); //console.dir('testing Session ' + req.session.Client); console.log('did not search database for '+ req.subdomains[0]); //console.log(JSON.stringify(req.session.Client,null,4)); next(); } else{ Clients.findOne({subdomain: req.subdomains[0]},function (err,client) { if(!err){ if(!client){ //res.send(client); res.send(403,'Sorry! you cant see that.'); } else{ console.log('searched database for '+ req.subdomains[0]); //console.log(JSON.stringify(client,4)); //console.log(client); // req.session.tester = "moyo cow"; req.session.Client = client; return next(); } } else{ console.log(err); return next(err) } }); } } } module.exports = clientlistener;
setclientdb中间件:
我再次检查一下,确保客户端有效.然后打开与会话检索的信息到客户端数据库的连接.
我还确保将所有活动连接存储到全局对象中,以便在每次请求时阻止与数据库的新连接(我们不想使用连接来覆盖每个客户端的mongodb服务器).
var mongoose = require('mongoose'); //var dynamicConnection = require('../models/dynamicMongoose'); function setclientdb() { return function(req,next){ //check if client has an existing db connection /*** Check if client db is connected and pooled *****/ if(/*typeof global.App.clientdbconn === 'undefined' && */ typeof(req.session.Client) !== 'undefined' && global.App.clients[req.session.Client.name] !== req.subdomains[0]) { //check if client session,matches current client if it matches,establish new connection for client if(req.session.Client && req.session.Client.name === req.subdomains[0] ) { console.log('setting db for client ' + req.subdomains[0]+ ' and '+ req.session.Client.dbUrl); client = mongoose.createConnection(req.session.Client.dbUrl /*,dbconfigoptions*/); client.on('connected',function () { console.log('Mongoose default connection open to ' + req.session.Client.name); }); // When the connection is disconnected client.on('disconnected',function () { console.log('Mongoose '+ req.session.Client.name +' connection disconnected'); }); // If the Node process ends,close the Mongoose connection process.on('SIGINT',function() { client.close(function () { console.log(req.session.Client.name +' connection disconnected through app termination'); process.exit(0); }); }); //If pool has not been created,create it and Add new connection to the pool and set it as active connection if(typeof(global.App.clients) === 'undefined' || typeof(global.App.clients[req.session.Client.name]) === 'undefined' && typeof(global.App.clientdbconn[req.session.Client.name]) === 'undefined') { clientname = req.session.Client.name; global.App.clients[clientname] = req.session.Client.name;// Store name of client in the global clients array activedb = global.App.clientdbconn[clientname] = client; //Store connection in the global connection array console.log('I am now in the list of active clients ' + global.App.clients[clientname]); } global.App.activdb = activedb; console.log('client connection established,and saved ' + req.session.Client.name); next(); } //if current client,does not match session client,then do not establish connection else { delete req.session.Client; client = false; next(); } } else { if(typeof(req.session.Client) === 'undefined') { next(); } //if client already has a connection make it active else{ global.App.activdb = global.App.clientdbconn[req.session.Client.name]; console.log('did not make new connection for ' + req.session.Client.name); return next(); } } } } module.exports = setclientdb;
最后但是同样重要的
由于我使用的是黑猫和本地mongo的组合,我们必须在运行时编译我们的模型.请参阅下文
将其添加到您的app.js
// require your models directory var models = require('./models'); // Create models using mongoose connection for use in controllers app.use(function db(req,next) { req.db = { User: global.App.activdb.model('User',models.agency_user,'users') //Post: global.App.activdb.model('Post',models.Post,'posts') }; return next(); });
说明:
就像我之前所说的,我创建了一个全局对象来存储活动数据库连接对象:global.App.activdb
然后我使用此连接对象来创建(编译)mongoose模型,之后我将它存储在req对象的db属性中:req.db.我这样做,以便我可以在我的控制器中访问我的模型,例如.
我的用户控制器示例:
exports.list = function (req,res) { req.db.User.find(function (err,users) { res.send("respond with a resource" + users + 'and connections ' + JSON.stringify(global.App.clients,4)); console.log('Worker ' + cluster.worker.id + ' running!'); }); };
最后我会回来清理一下.如果有人想帮助我,那就好了