Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/370.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 从nodejs到mongodb或mongoose的动态数据库连接_Javascript_Node.js_Mongodb_Express_Mongoose - Fatal编程技术网

Javascript 从nodejs到mongodb或mongoose的动态数据库连接

Javascript 从nodejs到mongodb或mongoose的动态数据库连接,javascript,node.js,mongodb,express,mongoose,Javascript,Node.js,Mongodb,Express,Mongoose,我正在尝试创建一个多租户应用程序(saas),其中每个客户端都有自己的数据库 我的情况是: 我创建了一个中间件,可以根据子域确定客户机是谁,然后从通用数据库检索客户机的数据库连接信息。我不知道如何为此客户端建立连接对象,以便能够在我的控制器中使用。我应该在中间件中还是在控制器中这样做?如果它在模型中,我如何传递连接字符串和参数(我可以使用会话,但我不知道如何从模型中访问会话) 我该如何做以下工作 组织:在哪里为客户端动态创建数据库连接 将连接参数注入/传递到控制器或模型(在其中进行连接定义) 建

我正在尝试创建一个多租户应用程序(saas),其中每个客户端都有自己的数据库

我的情况是:

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

我该如何做以下工作

  • 组织:在哪里为客户端动态创建数据库连接
  • 将连接参数注入/传递到控制器或模型(在其中进行连接定义)
  • 建立动态连接后,如何为该客户端全局访问它
  • 这是我的中间件的一个例子,我想创建一个mongoose连接,我想使其成为动态的(传入客户端的连接信息):

    如何从控制器内部访问此连接对象?还是从模型中


    谢谢。

    这是为了帮助其他人,他们可能会发现自己的处境与我相似。我希望它能标准化。我不认为每次有人需要开发多租户应用程序时,我们都需要重新设计轮子

    本例描述了一个多租户结构,每个客户机都有自己的数据库。 就像我说的,可能有更好的方法,但因为我自己没有得到帮助,这是我的解决方案

    因此,此解决方案的目标如下:

    • 每个客户端由子域标识,例如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, 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中间件: 我再次检查所有内容,确保客户有效。然后,使用从会话检索到的信息打开到客户机数据库的连接

    我还确保将所有活动连接存储到一个全局对象中,以防止每次请求时都有新的数据库连接(我们不想让每个客户端mongodb服务器的连接过载)

    最后但并非最不重要 因为我使用的是mongoose和原生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, 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();
    });
    
    说明:

    正如我前面所说,我创建了一个全局对象来存储活动数据库连接对象:
    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, null, 4));
            console.log('Worker ' + cluster.worker.id + ' running!');
        });
    
    };
    
    我最终会回来把这些清理干净。如果有人想帮助我,那就太好了。

    大家好,这里有一个更新得多的解决方案。 因此,此解决方案的目标如下:

    • 每个客户端由子域标识,例如client1.application.com
    • 应用程序检查子域是否有效
    • 应用程序从主数据库中查找并获取连接信息(数据库url、凭据等)
    • 应用程序连接到客户端数据库(几乎移交给客户端)
    • 应用程序采取措施确保完整性和资源管理(例如,对同一客户端的成员使用相同的数据库连接,而不是建立新连接)
    更新
    • 使用承诺
    • 模型的自动导入和编译
    • 新中间件;modelsinit(用于自动导入和编译mongoose模型)
    • 清理中间件(setclientdb、clientlistener、modelsInit)
    请参阅下面的一些解释 **

    modelsInit中间件 ** 特征

    • 测试模型是否已经编译。如果是,跳过
    • 测试请求是否不是租户请求;i、 e(请求应用程序主页、管理页面等)

    Todo:进一步解释

    ClientListener.js setclientdb.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();
    });
    
    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!');
        });
    
    };
    
    'use strict';
    /**
     * Created by moyofalaye on 3/17/14.
     */
    
    var path = require('path');
    var config = require('../../config/config');
    
    // Globbing model files
    
    config.getGlobbedFiles('./app/models/*.js').forEach(function (modelPath) {
        require(path.resolve(modelPath));
    
    });
    
    
    
    function modelsInit() {
        return function (req, res, next) {
    
    //console.log(req.subdomains[0]);
            switch (req.subdomains[0]) {
                case 'www':
                case undefined:
                    return next();
                    break;
                case 'admin':
                    return next();
                    break;
    //            default:
    //              return
            }
            var clientname = req.session.Client.name;
    
        // test if models are not already compiled if so, skip
        if (/*typeof req.db === 'undefined' && */ typeof global.App.clientModel[clientname] === 'undefined') {
            req.db = {};
         //Get files from models directory
                config.getGlobbedFiles('./app/models/clientmodels/**/*.js').forEach(function (modelPath) {
                console.log('the filepath is ' + modelPath);
                //Deduce/ extrapulate model names from the file names
                //Im not very good with regxp but this is what i had to do, to get the names from the filename e.g users.server.models.js (this is my naming convention, so as not to get confused with server side models and client side models
    
                var filename = modelPath.replace(/^.*[\\\/]/, '');
                var fullname = filename.substr(0, filename.lastIndexOf('.'));
                var endname = fullname.indexOf('.');
                var name = fullname.substr(0, endname);
                req.db[name] = require(path.resolve(modelPath))(global.App.activdb);
                console.log('the filename is ' + name);
            });
    
            global.App.clientModel[clientname] = req.db;
    
            console.log(global.App.clients);
    
            return next();
        }
        // since models exist, pass it to request.db for easy consumption in controllers
        req.db = global.App.clientModel[clientname];
        return next();
        };
    }
    
    module.exports = modelsInit;
    
    var config = require('../../config/config');
    var Clients = require('../models/clients');
    var basedomain = config.baseDomain;
    var allowedSubs = {'admin': true, 'www': true};
    allowedSubs[basedomain] = true;
    
    //console.dir(allowedSubs);
    
    function clientlistener() {
        return function (req, res, next) {
            //check if client has already been recognized
            if (req.subdomains[0] in allowedSubs || typeof req.subdomains[0] == 'undefined' || req.session.Client && req.session.Client.name === req.subdomains[0]) {
                console.log('did not search database for ' + req.subdomains[0]);
                //console.log(JSON.stringify(req.session.Client, null, 4));
                return next();
            }
    
            //look for client in database
            else {
    
                Clients.findOne({subdomain: req.subdomains[0]}, function (err, client) {
                    if (!err) {
                        //if client not found
                        if (!client) {
                            //res.send(client);
                            res.status(403).send('Sorry! you cant see that.');
                            console.log(client);
                        }
                        // client found, create session and add client
                        else {
                            console.log('searched database for ' + req.subdomains[0]);
                            req.session.Client = client;
                            return next();
                        }
                    }
                    else {
                        console.log(err);
                        return next(err)
                    }
    
                });
            }
    
        }
    }
    
    module.exports = clientlistener;
    
    var client;
    var clientname;
    var activedb;
    
    var Promise = require("bluebird");
    Promise.promisifyAll(require("mongoose"));
    //mongoose = require('mongoose');
    
    
    function setclientdb() {
        return function (req, res, next) {
            //check if client is not valid
            if (typeof(req.session.Client) === 'undefined' || req.session.Client && req.session.Client.name !== req.subdomains[0]) {
                delete req.session.Client;
                client = false;
                return next();
            }
            //if client already has an existing connection make it active
            else if (global.App.clients.indexOf(req.session.Client.name) > -1) {
                global.App.activdb = global.App.clientdbconn[req.session.Client.name]; //global.App.clientdbconnection is an array of or established connections
                console.log('did not make new connection for ' + req.session.Client.name);
                return next();
            }
            //make new db connection
            else {
                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);
                    //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.push(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 and set it as the current active database
                        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);
                        return next();
                    }
                });
                // 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);
                    });
                });
            }
    
    
        }
    }
    
    module.exports = setclientdb;