Mongoose и несколько баз данных в одном проекте node.js


123

Я делаю проект Node.js, который содержит подпроекты. Один подпроект будет иметь одну базу данных Mongodb, а Mongoose будет использоваться для упаковки и запросов к базе данных. Но проблема в том

  • Mongoose не позволяет использовать несколько баз данных в одном экземпляре mongoose, поскольку модели строятся на одном соединении.
  • Чтобы использовать несколько экземпляров mongoose, Node.js не позволяет использовать несколько экземпляров модуля, поскольку в нем есть система кеширования require(). Я знаю, что отключить кеширование модулей в Node.js, но я думаю, что это не лучшее решение, так как оно нужно только для мангуста.

    Я пробовал использовать createConnection()и openSet()в мангусте, но это не было решением.

    Я попытался глубоко скопировать экземпляр мангуста ( http://blog.imaginea.com/deep-copy-in-javascript/ ), чтобы передать новые экземпляры мангуста в подпроект, но он бросил RangeError: Maximum call stack size exceeded.

Я хочу знать, есть ли способы использовать несколько баз данных с мангустом или какое-либо решение этой проблемы? Потому что я считаю, что мангуст довольно простой и быстрый. Или любые другие модули в качестве рекомендаций?

Ответы:


38

Вы можете сделать одну вещь: у вас могут быть подпапки для каждого проекта. Итак, установите mongoose в эти подпапки и require () mongoose из собственных папок во всех подпапках. Не из корня проекта или из глобального. Итак, один подпроект, одна установка мангуста и один экземпляр мангуста.

-app_root/
--foo_app/
---db_access.js
---foo_db_connect.js
---node_modules/
----mongoose/
--bar_app/
---db_access.js
---bar_db_connect.js
---node_modules/
----mongoose/

В foo_db_connect.js

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/foo_db');
module.exports = exports = mongoose;

В bar_db_connect.js

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/bar_db');
module.exports = exports = mongoose;

В файлах db_access.js

var mongoose = require("./foo_db_connect.js"); // bar_db_connect.js for bar app

Теперь вы можете получить доступ к нескольким базам данных с помощью mongoose.


2
Это означает, что у каждого проекта будет свое подключение. Вы не сможете управлять 100 тыс. Подключений. Думаю, было бы лучше использовать useDbкоманду, которая использует тот же пул соединений.
xpepermint

1
xpepermint, можете ли вы показать пример для useDb - У меня сейчас эта проблема stackoverflow.com/questions/37583198/…
Lion789

4
Это похоже на огромную нагрузку на проект. ты так не думаешь?
Эшвар Прасад Ядданапуди 02

1
Совершенно нормально иметь несколько разных экземпляров соединения (например, для пользовательской БД, сеансовой БД и для данных приложения) для каждого приложения. Это не «огромная нагрузка» и не вызовет проблем с масштабированием, это обычный вариант использования.
Iain Collins

Ты мой лучший друг! Огромное спасибо! меня устраивает! Спасибо!
Бируэль Рик,

215

Согласно прекрасному руководству , createConnection() может использоваться для подключения к нескольким базам данных.

Однако вам необходимо создать отдельные модели для каждого соединения / базы данных:

var conn      = mongoose.createConnection('mongodb://localhost/testA');
var conn2     = mongoose.createConnection('mongodb://localhost/testB');

// stored in 'testA' database
var ModelA    = conn.model('Model', new mongoose.Schema({
  title : { type : String, default : 'model in testA database' }
}));

// stored in 'testB' database
var ModelB    = conn2.model('Model', new mongoose.Schema({
  title : { type : String, default : 'model in testB database' }
}));

Я почти уверен, что вы можете поделиться схемой между ними, но вы должны проверить, чтобы убедиться.


4
Да, я думаю, что именованные соединения и общая схема - это лучший вариант. По примеру Роберта, для каждого соединения потребуется уникальная модель.
Саймон Холмс

21
Также useDb()в 3.8 доступна проверка для совместного использования базового пула соединений: github.com/LearnBoost/mongoose/wiki/…
aaronheckmann

1
Предположим, у меня есть автоматически сгенерированная база данных (скажем, номер базы данных). Ни одного или двух. Есть ли способ подключиться к ним без создания отдельной модели для каждой базы данных?
Anooj Krishnan G

1
@AnoojKrishnanG Я не думаю, что это возможно, нет. Вам необходимо создать модель для каждой базы данных отдельно. Однако, как я уже сказал в своем ответе, вы можете поделиться схемой между соединениями, что может сэкономить время на кодирование.
robertklep

1
Вы можете использовать схему в разных моделях и, следовательно, в БД. var newSchema = new mongoose.Schema({ ... }), var model2 = conn1.model('newModel', newSchema),var model2 = conn2.model('newModel', newSchema)
даровать

42

Довольно поздно, но это может кому-то помочь. Текущие ответы предполагают, что вы используете один и тот же файл для своих подключений и моделей.

В реальной жизни высока вероятность того, что вы разбиваете свои модели на разные файлы. Вы можете использовать что-то вроде этого в своем основном файле:

mongoose.connect('mongodb://localhost/default');

const db = mongoose.connection;

db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', () => {
  console.log('connected');
});

как это описано в документации. А затем в файлах модели сделайте что-то вроде следующего:

import mongoose, { Schema } from 'mongoose';

const userInfoSchema = new Schema({
  createdAt: {
    type: Date,
    required: true,
    default: new Date(),
  },
  // ...other fields
});

const myDB = mongoose.connection.useDb('myDB');

const UserInfo = myDB.model('userInfo', userInfoSchema);

export default UserInfo;

Где myDB - имя вашей базы данных.


Спасибо - я смог использовать 3 разные базы данных в одном приложении, используя: const mongoose = require ('mongoose'); const Schema = mongoose.Schema; const mySchema = новая схема ({}); const mydbvar = mongoose.connection.useDb ('mydb') module.exports = mydbvar.model ('myCollection', MySchema);
Джонатан Энслин

2
Определенно лучший и самый реальный пример. Подключитесь к базе данных по умолчанию (точно так же, как если бы вы использовали что-то вроде SQL Server), а затем воспользуйтесь преимуществом useDb для нацеливания вашего DML на соответствующую базу данных. (Очень полезно для того, чтобы ваши пользователи находились в одной базе данных, а ваши данные - в другой.) Нет необходимости создавать несколько соединений, когда в конечном итоге вы отправляете запросы на один и тот же сервер. Теперь, если вы подключались к двум разным серверам, это совсем другой котел.
Newclique

2
Как сказал @Wade, насколько я понимаю, это решение работает только тогда, когда все базы данных находятся на одном сервере. Неясно, отвечает ли это на вопрос ОП, а ИМО немного вводит в заблуждение.
joniba

Это как раз то, что мне нужно для миграции с MongoDB Atlas test, а также для предотвращения множественных подключений. Тем не менее, я также .dbв end ( const v1 = mongoose.connection.useDb('test').db), поскольку старый db не требует управления мангустом.
Polv

37

В качестве альтернативного подхода Mongoose экспортирует конструктор для нового экземпляра в экземпляр по умолчанию. Так что что-то подобное возможно.

var Mongoose = require('mongoose').Mongoose;

var instance1 = new Mongoose();
instance1.connect('foo');

var instance2 = new Mongoose();
instance2.connect('bar');

Это очень полезно при работе с отдельными источниками данных, а также когда вы хотите иметь отдельный контекст базы данных для каждого пользователя или запроса. Вам нужно будет быть осторожным, так как при этом можно создать МНОГО подключений. Обязательно вызывайте disconnect (), когда экземпляры не нужны, а также ограничивайте размер пула, создаваемого каждым экземпляром.


1
это еще один способ написать «ответ выше» ?
правин 03

11
Это не тот ответ, что лучше. Приведенный выше ответ без необходимости устанавливает несколько копий Mongoose.
Мартин Вальдес де Леон,

как мне делать запросы, используя этот метод?
Shahidfoy

2
await instance1.connection.collection('foo').insert({ foo: 'bar', }) await instance2.connection.collection('foo').insert({ foo: 'zoo', })
Абдалла Аль Бармави

На самом деле лучше работать в моем случае, так как у меня совершенно разные учетные данные для каждого соединения, не говоря уже о моделях и базах данных.
tzn

0

Немного оптимизированное (по крайней мере для меня) решение. напишите это в файл db.js и потребуйте его там, где это необходимо, и вызовите его с помощью вызова функции, и все готово.

   const MongoClient = require('mongodb').MongoClient;
    async function getConnections(url,db){
        return new Promise((resolve,reject)=>{
            MongoClient.connect(url, { useUnifiedTopology: true },function(err, client) {
                if(err) { console.error(err) 
                    resolve(false);
                }
                else{
                    resolve(client.db(db));
                }
            })
        });
    }

    module.exports = async function(){
        let dbs      = [];
        dbs['db1']     = await getConnections('mongodb://localhost:27017/','db1');
        dbs['db2']     = await getConnections('mongodb://localhost:27017/','db2');
        return dbs;
    };
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.