Mongoose e vários bancos de dados no projeto node.js único

122

Estou fazendo um projeto Node.js que contém subprojetos. Um subprojeto terá um banco de dados Mongodb e o Mongoose será usado para agrupar e consultar o banco de dados. Mas o problema é

  • O Mongoose não permite usar vários bancos de dados em uma única instância de mangusto, pois os modelos são construídos em uma conexão.
  • Para usar várias instâncias de mangusto, o Node.js não permite várias instâncias de módulo, pois possui o sistema de cache require(). Eu sei desativar o cache do módulo no Node.js, mas acho que não é a boa solução, pois é apenas necessário para o mangusto.

    Eu tentei usar createConnection()e openSet()em mangusto, mas não era a solução.

    Tentei copiar profundamente a instância do mangusto ( http://blog.imaginea.com/deep-copy-in-javascript/ ) para passar novas instâncias do mangusto para o subprojeto, mas está sendo lançada RangeError: Maximum call stack size exceeded.

Eu quero saber se há alguma maneira de usar vários bancos de dados com mangusto ou alguma solução alternativa para esse problema? Porque acho que o mangusto é bem fácil e rápido. Ou quaisquer outros módulos como recomendações?

pupot
fonte

Respostas:

37

Uma coisa que você pode fazer é ter subpastas para cada projeto. Portanto, instale o mangusto nessas subpastas e exija () o mangusto de suas próprias pastas em cada sub-aplicativo. Não da raiz do projeto ou da global. Então, um subprojeto, uma instalação de mangusto e uma instância de mangusto.

-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/

Em foo_db_connect.js

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

Em bar_db_connect.js

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

Nos arquivos db_access.js

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

Agora, você pode acessar vários bancos de dados com o mangusto.

yemaw
fonte
2
Isso significa que todo projeto terá sua própria conexão. Você não poderá gerenciar 100k conexões. Eu acho que seria melhor usar o useDbcomando que usa o mesmo pool de conexão.
Xpepermint
1
xpepermint você é capaz de mostrar um exemplo para useDb - Estou tendo esta questão atualmente stackoverflow.com/questions/37583198/...
Lion789
4
Isso parece um enorme fardo para o projeto. você não acha?
Eshwar Prasad Yaddanapudi 02/08/16
1
Ter algumas instâncias de conexão diferentes (por exemplo, para um banco de dados do usuário, um banco de dados da sessão e para dados do aplicativo) por aplicativo é absolutamente bom. Não é 'um fardo enorme' ou causa problemas de dimensionamento e é um caso de uso comum.
Iain Collins
Você é o melhor meu amigo! Muito obrigado! funciona para mim! obrigado!
22719 Biruel Rick
214

De acordo com o manual , createConnection() pode ser usado para conectar-se a vários bancos de dados.

No entanto, você precisa criar modelos separados para cada conexão / banco de dados:

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' }
}));

Tenho certeza de que você pode compartilhar o esquema entre eles, mas é necessário verificar para ter certeza.

robertklep
fonte
4
Sim, conexões nomeadas e um esquema compartilhado são o caminho a seguir, eu acho. Cada conexão precisará de um modelo único, como no exemplo de Robert.
Simon Holmes
21
Também check-out useDb()disponível em 3.8 para compartilhar o pool de conexão subjacente: github.com/LearnBoost/mongoose/wiki/...
aaronheckmann
1
Suponha que eu tenha um banco de dados gerado automaticamente (digamos n número de banco de dados). Nem um nem dois. Existe alguma maneira de conectar-se a eles sem criar um modelo separado para cada banco de dados?
Anooj Krishnan G
1
@AnoojKrishnanG Eu não acho que isso é possível, não. Você precisa criar o modelo em cada banco de dados separadamente. No entanto, como já afirmei na minha resposta, você poderá compartilhar os esquemas entre as conexões, o que pode economizar tempo de codificação.
Robertklep
1
Você pode compartilhar o esquema entre os diferentes modelos e, portanto, DBs. var newSchema = new mongoose.Schema({ ... }), var model2 = conn1.model('newModel', newSchema),var model2 = conn2.model('newModel', newSchema)
conceder
41

Muito tarde, mas isso pode ajudar alguém. As respostas atuais assumem que você está usando o mesmo arquivo para suas conexões e modelos.

Na vida real, há uma grande chance de você estar dividindo seus modelos em arquivos diferentes. Você pode usar algo parecido com isto em seu arquivo principal:

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

const db = mongoose.connection;

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

que é exatamente como é descrito nos documentos. E então nos arquivos de modelo, faça algo como o seguinte:

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;

Onde myDB é o nome do seu banco de dados.

Tahnik Mustasin
fonte
Obrigado - Consegui usar 3 bancos de dados diferentes em um único aplicativo usando: const mongoose = require ('mongoose'); const Esquema = mangusto.Schema; const mySchema = novo esquema ({}); const mydbvar = mongoose.connection.useDb ('mydb') module.exports = mydbvar.model ('myCollection', MySchema);
Johnathan Enslin
2
Definitivamente o melhor e mais exemplo do mundo real. Conecte-se ao banco de dados padrão (como se estivesse usando algo como o SQL Server) e aproveite o useDb para direcionar seu DML ao banco de dados apropriado. (Muito útil para manter seus usuários em um banco de dados e seus dados em outro.) Não é necessário começar a fazer várias conexões quando, finalmente, você estiver enviando solicitações para o mesmo servidor. Agora, se você estava se conectando a dois servidores diferentes, isso é uma chaleira diferente de peixe.
Newclique 10/09/18
2
Como o @Wade disse, até onde eu entendo, essa solução só funciona quando todos os bancos de dados estão no mesmo servidor. Não está claro se isso responde à pergunta do OP e a OMI é um pouco enganadora.
joniba
Isso é exatamente o que eu precisava para a migração do MongoDB Atlas teste também para evitar ter várias conexões. No entanto, eu também .dbno final ( const v1 = mongoose.connection.useDb('test').db), pois o banco de dados antigo não precisa ser gerenciado pelo mangusto.
Polv 26/07
37

Como uma abordagem alternativa, o Mongoose exporta um construtor para uma nova instância na instância padrão. Então, algo assim é possível.

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

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

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

Isso é muito útil ao trabalhar com fontes de dados separadas e também quando você deseja ter um contexto de banco de dados separado para cada usuário ou solicitação. Você precisará ter cuidado, pois é possível criar muitas conexões ao fazer isso. Certifique-se de chamar o método desconectar () quando as instâncias não forem necessárias e também limitar o tamanho do pool criado por cada instância.

Eric
fonte
1
Essa é outra maneira de escrever 'Acima da resposta' ?
Pravin
11
Esta não é a resposta acima, é melhor. A resposta acima instala várias cópias do Mongoose desnecessariamente.
Martín Valdés de León
como eu faria consultas usando esse método?
shahidfoy
2
await instance1.connection.collection('foo').insert({ foo: 'bar', }) await instance2.connection.collection('foo').insert({ foo: 'zoo', })
Abdallah Al Barmawi 26/07/19
De fato, é melhor trabalhar no meu caso, pois tenho credenciais completamente diferentes para cada conexão, sem falar em modelos e bancos de dados.
tzn
0

Uma solução um pouco otimizada (pelo menos para mim). grave isso em um arquivo db.js e exija isso sempre que necessário e chame-o com uma chamada de função e você estará pronto.

   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;
    };
PKInd007
fonte