MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Dynamiczne połączenie bazy danych z mongodb lub mongoose z nodejs

Ma to pomóc innym, którzy mogą znaleźć się w podobnej sytuacji jak ja. Mam nadzieję, że da się to ustandaryzować. Nie sądzę, że powinniśmy wymyślać koło na nowo za każdym razem, gdy ktoś potrzebuje aplikacji dla wielu najemców.

Ten przykład opisuje strukturę wielodostępną, w której każdy klient ma własną bazę danych. Jak powiedziałem, może być lepszy sposób na zrobienie tego, ale ponieważ sam nie otrzymałem pomocy, to było moje rozwiązanie.

Oto cele tego rozwiązania:

  • każdy klient jest identyfikowany przez subdomenę, np. client1.application.com,
  • aplikacja sprawdza, czy subdomena jest prawidłowa,
  • aplikacja wyszukuje i uzyskuje informacje o połączeniu (adres URL bazy danych, poświadczenia itp.) z głównej bazy danych,
  • aplikacja łączy się z bazą danych klienta (w dużej mierze przekazuje ją klientowi),
  • Aplikacja podejmuje środki w celu zapewnienia integralności i zarządzania zasobami (np. używa tego samego połączenia z bazą danych dla członków tego samego klienta, zamiast tworzyć nowe połączenie).

Oto kod

w swoim app.js plik

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

Stworzyłem dwa oprogramowanie pośredniczące :

  • clientListener - do identyfikacji klienta łączącego się,
  • setclientdb - pobiera dane klienta z bazy danych Master, po zidentyfikowaniu klienta, a następnie nawiązuje połączenie z bazą danych klienta.

Oprogramowanie pośredniczące ClientListener

Sprawdzam, kim jest klient, sprawdzając subdomenę z obiektu żądania. Robię kilka testów, aby upewnić się, że klient jest poprawny (wiem, że kod jest niechlujny i można go oczyścić). Po upewnieniu się, że klient jest ważny, przechowuję informacje o kliencie w sesji. Sprawdzam również, czy jeśli informacje o klientach są już przechowywane w sesji, nie ma potrzeby ponownego odpytywania bazy danych. Musimy tylko upewnić się, że poddomena żądania pasuje do tej, która jest już zapisana w sesji.

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;

oprogramowanie pośredniczące setclientdb:

Sprawdzam wszystko jeszcze raz upewniając się, że klient jest ważny. Następnie zostaje otwarte połączenie z bazą danych klienta z informacjami pobranymi z sesji.

Upewniam się również, że wszystkie aktywne połączenia są przechowywane w globalnym obiekcie, aby zapobiec nowym połączeniom do bazy danych przy każdym żądaniu (nie chcemy przeciążać każdego klienta serwera mongodb połączeniami).

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;

Ostatnia, ale nie najmniejsza

Ponieważ używam kombinacji mangusty i rodzimego mongo, musimy kompilować nasze modele w czasie wykonywania. Zobacz poniżej

Dodaj to do swojego 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();
});

Wyjaśnienie:

Tak jak powiedziałem wcześniej, stworzyłem globalny obiekt do przechowywania aktywnego obiektu połączenia z bazą danych:global.App.activdb

Następnie używam tego obiektu połączenia do tworzenia (kompilacji) modelu mangusty, po zapisaniu go we właściwości db obiektu req:req.db . Robię to, aby na przykład mieć dostęp do moich modeli w moim kontrolerze.

Przykład mojego kontrolera użytkowników:

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

};

Wrócę i w końcu to posprzątam. Jeśli ktoś chce mi pomóc, to miło.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Sprawdź, czy istnieje baza danych mongodb?

  2. Pobierz wartości jako tablicę elementów po $lookup

  3. MongoDB - Wiele $ lub operacji

  4. MongoDB $isoWeek

  5. Co to jest TransientTransactionError w Mongoose (lub MongoDB)?