sql >> Databasteknik >  >> NoSQL >> MongoDB

Dynamisk databasanslutning till mongodb eller mongoose från nodejs

Detta för att hjälpa andra som kan hamna i liknande situation som jag. Jag hoppas att det skulle kunna standardiseras. Jag tror inte att vi ska behöva uppfinna hjulet på nytt varje gång någon behöver göra en ansökan med flera hyresgäster.

Det här exemplet beskriver en struktur för flera hyresgäster där varje klient har sin egen databas. Som jag sa, det kan finnas ett bättre sätt att göra detta på, men eftersom jag inte fick hjälp själv var detta min lösning.

Så här är målen med denna lösning:

  • varje klient identifieras av underdomän, t.ex. client1.application.com,
  • applikation kontrollerar om underdomänen är giltig,
  • applikationen letar upp och hämtar anslutningsinformation (databaswebbadress, referenser, etc) från huvuddatabasen,
  • applikation ansluter till klientdatabas (i stort sett överlämnas till klienten),
  • applikationen vidtar åtgärder för att säkerställa integritet och resurshantering (t.ex. använd samma databasanslutning för medlemmar av samma klient istället för att skapa en ny anslutning).

Här är koden

i din app.js fil

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

Jag har skapat två mellanprogram:

  • clientListener - för att identifiera klienten som ansluter,
  • setclientdb - hämtar klientinformation från huvuddatabasen, efter att klienten har identifierats, och upprättar sedan anslutning till klientdatabasen.

clientListener-mellanprogram

Jag kontrollerar vem klienten är genom att kolla underdomänen från förfrågningsobjektet. Jag gör ett gäng kontroller för att vara säker på att klienten är giltig (jag vet att koden är rörig och kan göras renare). Efter att ha säkerställt att klienten är giltig lagrar jag klientinformationen i sessionen. Jag kontrollerar också att om klientinformationen redan är lagrad i sessionen finns det inget behov av att fråga databasen igen. Vi behöver bara se till att underdomänen för begäran matchar den som redan är lagrad i sessionen.

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 mellanprogram:

Jag kontrollerar allt igen och säkerställer att klienten är giltig. Därefter öppnas anslutningen till klientens databas med informationen som hämtats från sessionen.

Jag ser också till att lagra alla aktiva anslutningar i ett globalt objekt, för att förhindra nya anslutningar till databasen vid varje begäran (vi vill inte överbelasta varje klients mongodb-server med anslutningar).

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;

Sist men inte minst

Eftersom jag använder en kombination av mongoose och infödd mongo, måste vi sammanställa våra modeller under körning. Se nedan

Lägg till detta i din 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();
});

Förklaring:

Som jag sa tidigare skapade jag ett globalt objekt för att lagra det aktiva databasanslutningsobjektet:global.App.activdb

Sedan använder jag det här anslutningsobjektet för att skapa (kompilera) mongoose-modell, efter att jag lagrat den i db-egenskapen för req-objektet:req.db . Jag gör detta för att jag ska kunna komma åt mina modeller i min kontroller så här till exempel.

Exempel på min användarkontroller:

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!');
    });

};

Jag kommer tillbaka och städar upp det här så småningom. Om någon vill hjälpa mig är det trevligt.



  1. Använda COD och CML för att bygga applikationer som förutsäger lagerdata

  2. Grattis på födelsedagen Apache HBase! 10 år av motståndskraft, stabilitet och prestanda

  3. Redisson, arbetskö/dequeu. Strategier för bearbetning av meddelande / element vid ofullständig meddelandehantering vid avstängning av system / pod

  4. mongodb sorteringsordning på _id