从nodejs到mongodb或mongoose的动态数据库连接 [英] Dynamic database connection to mongodb or mongoose from nodejs

查看:124
本文介绍了从nodejs到mongodb或mongoose的动态数据库连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我的情况是:



我创建了一个中间件,可以确定客户端基于子域的客户端,然后从通用数据库检索客户端的数据库连接信息。我不知道如何建立这个客户端的连接对象,以便能够在我的控制器中使用。我应该在中间件还是控制器中这样做?如果它在模型中,我如何传递连接字符串和参数(我可以使用会话,但我不知道如何从模型中访问会话)。



如何执行以下操作?


  1. 组织:动态地为客户端创建数据库连接?

  2. 将连接参数注入或传递到控制器或型号(连接定义)

  3. 在动态连接完成后,如何为该客户端访问全局? / li>

这是我的中间件的一个例子,我想创建一个我想要动态的(通过客户端连接信息):

  function clientlistener(){
return function(req,res,next){
console.dir('看我的子域'+ 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,凭据等),

  • 应用程序连接到客户端数据库(几乎交给客户端),

  • 应用程序采取措施确保完整性和资源管理(例如,为同一客户端的成员使用相同的数据库连接,而不是



以下是您的



code> app.js 文件

  app.use(clientListener()); //检查并识别有效的客户端
app.use(setclientdb()); //为有效客户设置数据库

我创建了两个中间件:




  • 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,res,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('没有搜索数据库'+ req.subdomains [0]);
//console.log(JSON.stringify(req.session.Client,null,4));
next();
}
$ {

Clients.findOne({subdomain:req.subdomains [0]},function(err,client){
if(!err) {
if(!client){
//res.send(client);
res.send(403,'对不起,你看不到这个)';
}
else {
console.log(''搜索数据库'+ req.subdomains [0]);
//console.log(JSON.stringify(client,null,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 =要求( '猫鼬'); 
// var dynamicConnection = require('../ models / dynamicMongoose');
函数setclientdb(){
返回函数(req,res,next){
//检查客户端是否有现有的数据库连接/ ***检查客户端数据库是否已连接和池化* **** /
if(/ * typeof global.App.clientdbconn ==='undefined'&& * / typeof(req.session.Client)!=='undefined'&&& .App.clients [req.session.Client.name]!== req.subdomains [0])
{
//检查客户端会话,匹配当前客户端是否匹配,建立新连接客户端
if(req.session.Client&& req.session.Client.name === req.subdomains [0])
{
console.log('将db设置为客户端'+ req.subdomains [0] +'和'+ 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);
});
//当连接断开连接时
client.on('disconnect',function(){
console.log('Mongoose'+ req.session.Client.name +'connection disconnect ');
});

//如果Node进程结束,关闭Mongoose连接
process.on('SIGINT',function(){
client.close(function(){
console.log(req.session.Client.name +'通过应用程序终止断开连接);
process.exit(0);
});
});

//如果尚未创建池,请创建它并将其添加到池中并将其设置为活动连接

if(typeof(global.App.clients) ==='undefined'|| typeof(global.App.clients [req.session.Client.name])==='undefined'&&&&"(global.App.clientdbconn [req.session.Client.name ])==='undefined')
{
clientname = req.session.Client.name;
global.App.clients [clientname] = req.session.Client.name; //在全局客户端数组中存储客户端的名称
activedb = global.App.clientdbconn [clientname] = client; //在全局连接数组中存储连接
console.log('我现在处于活动客户端列表+ global.App.clients [clientname]);
}
global.App.activdb = activedb;
console.log('建立客户端连接并保存'+ req.session.Client.name);
next();
}
//如果当前客户端,不匹配会话客户端,则不建立连接
else
{
delete req.session.Client;
client = false;
next();
}
}
else
{
if(typeof(req.session.Client)==='undefined')
{
下一个();
}
//如果客户端已经有一个连接使其活动
else {
global.App.activdb = global.App.clientdbconn [req.session.Client.name] ;
console.log('没有为'+ req.session.Client.name创建新连接);
return next();
}

}
}
}

module.exports = setclientdb;



最后但并非最不重要的



我正在使用猫鼬和本地mongo的组合,我们必须在运行时编译我们的模型。请参阅下面



将此添加到您的 app.js

  //需要你的模型目录
var models = require('./ models');

//使用mongoose连接创建使用控制器的模型
app.use(function db(req,res,next){
req.db = {
用户:global.App.activdb.model('User',models.agency_user,'users')
//发布: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(使用资源+ users +'和连接'+ JSON.stringify(global.App.clients,null,4));
console.log('Worker'+ cluster.worker .id +'running!');
});

};

我最终会回来清理它。如果有人想帮助我,那很好。


I am trying to create a multi-tenant app (saas), where each client has its own database.

My situation is:

I created a middleware that would determine who the client is based on a subdomain, then retrieve the client's database connection info from a general database. I don't know how to establish a connection object for this client so as to be able to use in my controllers. And should I do this in the middleware or in a controller? And if it's in the model, how do i pass the connection string and parameters (I could use session, but I don't know how to access session from within model).

How do i do the following?

  1. Organisation: where do I create the db connection for client dynamically?
  2. Inject/pass connection parameters to controller or model (where connection definition is made)
  3. After dynamic connection has been made, how do i access it globally for that client?

This is an example of my middleware, and i would like to create a mongoose connection which i would like to make dynamic (pass in client's connection info):

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();
       }
    }
}

How do I access this connection object from inside the controller? Or from the model?

Thank you.

解决方案

This is to help others who may find themselves in similar situation as I did. I hope that it could be standardized. I dont think we should have to reinvent the wheel every time someone needs to make a multi-tenant application.

This example describes a multi-tenant structure with each client having its own database. Like i said there might be a better way of doing this, but because i didn't get help myself, this was my solution.

So here are the goals this solution targets:

  • each client is identified by subdomain e.g client1.application.com,
  • application checks if subdomain is valid,
  • application looks up and obtains connection information (database url, credentials, etc) from master database,
  • application connects to client database ( pretty much hands over to client),
  • application takes measures to ensure integrity and resource management (e.g use the same database connection for members of the same client, rather than make new connection).

Here is the code

in your app.js file

app.use(clientListener()); // checks and identify valid clients
app.use(setclientdb());// sets db for valid clients

I've created two middlewares :

  • clientListener - to identify the client connecting,
  • setclientdb - gets client details from Master database, after client is identified, and then establishes connection to client database.

clientListener middleware

I check who the client is by checking the subdomain from the request object. I do a bunch of checks to be sure the client is valid (I know the code is messy, and can be made cleaner). After ensuring the client is valid, I store the clients info in session. I also check that if the clients info is already stored in session, there is no need to query the database again. We just need to make sure that the request subdomain, matches that which is already stored in session.

var Clients = require('../models/clients');
var basedomain = dbConfig.baseDomain;
var allowedSubs = {'admin':true, 'www':true };
allowedSubs[basedomain] = true;
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.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, null, 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 middleware:

I check everything again making sure that the client is valid. Then the connection to the client's database with the info retrieved from session is opened.

I also make sure to store all active connections into a global object, so as to prevent new connections to the database upon each request(we don't want to overload each clients mongodb server with connections).

var mongoose = require('mongoose');
//var dynamicConnection = require('../models/dynamicMongoose');
function setclientdb() {
    return function(req, res, 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;

Last but not the least

Since I am using a combination of mongoose and native mongo, We have to compile our models at run time. Please see below

Add this to your app.js

// require your models directory
var models = require('./models');

// Create models using mongoose connection for use in controllers
app.use(function db(req, res, next) {
    req.db = {
        User: global.App.activdb.model('User', models.agency_user, 'users')
        //Post: global.App.activdb.model('Post', models.Post, 'posts')
    };
    return next();
});

Explanation:

Like I said earlier on I created a global object to store the active database connection object: global.App.activdb

Then I use this connection object to create (compile) mongoose model, after i store it in the db property of the req object: req.db. I do this so that i can access my models in my controller like this for example.

Example of my Users controller:

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, null, 4));
        console.log('Worker ' + cluster.worker.id + ' running!');
    });

};

I will come back and clean this up eventually. If anyone wants to help me, that be nice.

这篇关于从nodejs到mongodb或mongoose的动态数据库连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆