2014-10-07 2 views
0

My CMS написан на Node.js + Express + Mongoose. Это многопользовательская CMS, и каждый сайт имеет свою собственную базу данных. Поэтому мне нужно было заставить Mongoose переключать соединение при каждом HTTP-запросе. Я посмотрел на какое-то решение или на кого-то, у кого было такое же состояние, но безуспешно. Так что это мое решение:Mongoose динамические модели, не могут использовать populate()

HTTP Request:

router.get('/site/pages', function (req, res) { 
    pagesBiz.list(req.session, function(err, list) { 
     //do stuff 
    }); 
}); 

БИЗ компонент (pagesBiz):

module.exports = { 
    list: function(session, callback) { 
     Page(session.database).find(callback); 
    } 
} 

Модель (Page)

var cached = {}; 
var getModel = function (database) { 
    if(! cached[database]) { 
     var conn = mongoose.createConnection('mongodb://localhost/' + database); 
     cached[database] = conn.model('Page', pageSchema); 
    } 

    return cached[database]; 
} 

module.exports = function(database) { 
    return getModel(database); 
} 

Итак, как это работает? Когда пользователь регистрируется в новом пользовательском сеансе, создается и привязывается к пользователю через куки-файл сеанса (я использую сеанс MongoStore + Express). Сеанс содержит имя базы данных, которое используется для динамического создания моделей Mongoose.

Он отлично работает, пользователи разных сайтов читают из своих собственных баз данных, не рискуя «столкновениями», с другой стороны мне приходится передавать сеанс (или имя базы данных) вокруг функций, но я предполагаю, что это как Node.js работает в многопоточном контексте.

Единственная проблема, когда я использую метод заселить(), я получаю эту ошибку:

f:\www\rudsjs\node_modules\mongoose\lib\connection.js:625 throw new MongooseError.MissingSchemaError(name); ^MissingSchemaError: Schema hasn't been registered for model "User". Use mongoose.model(name, schema) at NativeConnection.Connection.model (f:\www\rudsjs\node_modules\mongoose\lib\connection.js:625:11) at populate (f:\www\rudsjs\node_modules\mongoose\lib\model.js:2136:24) at Function.Model.populate (f:\www\rudsjs\node_modules\mongoose\lib\model.js:2101:5) at Object.cb (f:\www\rudsjs\node_modules\mongoose\lib\query.js:1159:16) at Object._onImmediate (f:\www\rudsjs\node_modules\mongoose\node_modules\mquery\lib\utils.js:137:16) at processImmediate [as _immediateCallback] (timers.js:336:15)

Process finished with exit code 8

Я попытался поджать модель перед вызовом Заселите() с помощью этого:

пользователя (session.database);

, но проблема, как представляется, связано с тем, как Mongoose кэширует модели (это не мое), я смотрел на connection.js

model = this.base.models[name]; 

    if (!model) { 
    throw new MongooseError.MissingSchemaError(name); 
    } 

так что я нужен способ, чтобы вставить мою модель внутри это.base.models. Есть ли у вас какие-либо идеи? У вас есть особенно лучшее решение для внедрения среды с несколькими сайтами/несколькими базами данных?

ответ

0

Я нашел решение. Я кэшировал модели, а не соединения, поэтому я создавал новое соединение Mongoose для каждой модели, поэтому Mongoose не смог загрузить другие модели, используя populate().

Мое решение: использовать глобальный объект Cache, который хранит соединения, которые будут использоваться для сборки всех моделей.

Cache глобального объект

module.exports = { 
Cache: { 
     database: {} 
    } 
} 

Модель (Page)

module.exports = function(session) { 
    if(! Cache.database[session.database]) { 
     debug("Create connection to " + session.database); 
     var conn = mongoose.createConnection('mongodb://localhost/' + session.database); 
     Cache.database[session.database] = conn; 
    } 

    debug("[rud] " + session.database + " model created"); 
    return Cache.database[session.database].model('Page', pageSchema); 
} 

Как вы можете видеть, все модели теперь будет один и то же соединение, хранящееся в Cache.database [сессии. база данных]

Смежные вопросы