如何根据登录用户将调用定向到不同的实例MongoDB?

时间:2017-04-10 13:26:31

标签: node.js mongodb express

我正在开发一个多租户Saas应用程序的项目,并且很难实现根据用户登录信息登录各种数据库的方法。现在,我只想在Sandbox数据库(用于演示目的,将定期擦除)和Alpha数据库(用于当前客户端测试和开发)之间分配流量。我编写了下面的中间件config.js,它在登录时检测用户ID并使用mongoose.createConnection()分配数据库对象。然后使用memory-cache将此键值对添加到商店。这是config.js代码:

var mcache = require('memory-cache'),
    Promise = require("bluebird"),
    mongoose = require('mongoose');

Promise.promisifyAll(require("mongoose"));
(function () {

    'use strict';

    var dbSand = mongoose.createConnection(process.env.DB_SAND);
    var dbAlpha = mongoose.createConnection(process.env.DB_ALPHA);

    function dbPathConfigMiddlewareWrapper (){
        return function  setDbPath(req, res, next){
            if ( req ){
                if (!mcache.get(req.session.id) && req.body.email){
                    var login = req.body.email;
                    if (login === 'demo@mysite.com'){
                        mcache.put(req.session.id, dbSand);
                    } else {
                        mcache.put(req.session.id, dbAlpha);
                    }
                } 
                req.dbPath = mcache.get(req.session.id);

                next();
            }

        };

    }

module.exports = dbPathConfigMiddlewareWrapper;

}());

到目前为止一切顺利。但是我在路由中调用正确的数据库是不成功的。当我刚刚使用单个数据库时,我可以轻松地使用它:

  var connStr = process.env.DBPATH;

  if(mongoose.connection.readyState === 0){
      mongoose.connect(connStr, function(err) {
          if (err) throw err;
          console.log('Successfully connected to MongoDB');
      });
    }

现在,我试图这样做无济于事:

  var connStr = req.dbPath;  //where req.dbPath is assigned in the config middleware above.

  if(connStr.connection.readyState === 0){
      mongoose.connect(req.dbPath, function(err) {
          if (err) throw err;
          console.log('Successfully connected to MongoDB');
      });
    }

非常感谢任何指导。这似乎应该更加直截了当,文档提到了它,但没有详细说明。

2 个答案:

答案 0 :(得分:0)

我认为,问题在于您将数据库对象保存到键值存储中。 mcache.put(req.session.id, dbSand);。这导致了if(connStr.connection.readyState === 0)中的错误。

您可以对对象进行字符串化。 mcache.put(req.session.id, JSON.stringify(dbSand));。并获取对象的字符串并将其解析为JSON,如var connStr = JSON.parse(req.dbPath);

答案 1 :(得分:0)

如果您手动创建连接,则无法致电mongoose.connect()

相反,你必须为每个连接注册你的模型,这有点像PITA,但据我所知,没有办法解决这个问题。可能需要对代码进行一些重组。

这里有一些关于如何设置类似内容的未经测试的代码。

您的中间件文件:

// Create connections
const registerModels = require('./register-models');
let dbSand = mongoose.createConnection(process.env.DB_SAND);
let dbAlpha = mongoose.createConnection(process.env.DB_ALPHA);

// Register your models for each connection.
registerModels(dbSand);
registerModels(dbAlpha);

function dbPathConfigMiddlewareWrapper() { ... }

寄存器models.js:

const mongoose = require('mongoose');
const Schema   = mongoose.Schema;

let UserSchema = new mongoose.Schema(...);

module.exports = function(conn) {
  conn.model('User', UserSchema);
};

这确实意味着您无法在路线中使用User.find(...),因为只有在您使用单一连接时才会使用{默认的连接mongoose.connect() ,你没有使用的。)

相反,你应该在你的路线中使用这样的东西:

req.dbPath.model('User').find(...);