2017-04-10 9 views
0

私はマルチテナントのSaasアプリケーションになるプロジェクトに取り組んでいます。ユーザーのログイン情報に応じてさまざまなデータベースにログインする方法を実装するのが難しいです。現在のところ、Sandboxデータベース(デモ用、定期的にワイプされる)とAlphaデータベース(現在のクライアントのテストと開発用)の間でトラフィックを分割したいだけです。私はログイン時にユーザIDを検出し、mongoose.createConnection()を使ってデータベースオブジェクトを割り当てる、以下のミドルウェアconfig.jsを作成しました。このキーと値のペアは、memory-cacheを使用してストアに追加されます。 config.jsコードは次のとおりです。ログインしているユーザに基づいて、別のインスタンスMongoDBにコールを誘導するにはどうすればよいですか?

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 === '[email protected]'){ 
         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'); 
     }); 
    } 

ここで任意の指導をいただければ幸いです。これははるかに簡単であるはずだと思われるドキュメントのように見えますが、ドキュメントはそれを暗に示していますが、詳しく説明していません。

+0

[この](http://stackoverflow.com/a/19475270/893780)。基本的に、異なるデータベース接続がある場合は、各接続に対してモデルを個別に登録する必要があります。 'mongoose.createConnection()'を使っているので、 'mongoose.connect()'は動作しません。 – robertklep

+0

ありがとう@robertklep、私はそれを読んだが、実装上2つの理由で不明であった。 1.私のデータベースのスキーマは同じですが、明らかに単純なインラインモデルだけがあります。これはスケーラブルではないようです。私は同じスキーマ(現在5つのモデル)を私がリファクタリングするときにあなたの推奨するアプローチは何ですか? 2. 'mongoose.createConnection()'を使用して接続を作成したら、すぐに両方に接続する必要がありますか?その場合、後で正しい接続にどのようにルーティングすればよいですか?または、操作ごとに明示的に接続を開いて閉じる必要がありますか?ありがとう – espressoAndCode

答えて

0

ここでは、データベースオブジェクトをキー値ストレージに保存していることが問題だと思います。 mcache.put(req.session.id, dbSand);if(connStr.connection.readyState === 0)にエラーが発生しました。

オブジェクトをストリング化することができます。 mcache.put(req.session.id, JSON.stringify(dbSand));。オブジェクトの文字列を取得し、var connStr = JSON.parse(req.dbPath);のようにJSONに解析します。

+0

申し訳ありませんが、これは正しい解決策ではありません。すぐに「接続に失敗しました」というエラーが発生し、サーバーがクラッシュします。 – espressoAndCode

+0

完全な解決策ではないかもしれません。あなたのキーバリュー(メモリキャッシュ)ストレージがオブジェクトをダイレクトに保存していますか? – Tolsee

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(...); 
関連する問題