Mongoose y múltiples bases de datos en un solo proyecto node.js

123

Estoy haciendo un proyecto Node.js que contiene subproyectos. Un subproyecto tendrá una base de datos Mongodb y Mongoose se utilizará para envolver y consultar la base de datos. Pero el problema es

  • Mongoose no permite el uso de varias bases de datos en una sola instancia de mangosta, ya que los modelos se basan en una sola conexión.
  • Para usar múltiples instancias de mangosta, Node.js no permite múltiples instancias de módulo ya que tiene un sistema de almacenamiento en caché en require(). Sé deshabilitar el almacenamiento en caché del módulo en Node.js, pero creo que no es la buena solución, ya que solo es necesario para la mangosta.

    He intentado usar createConnection()y openSet()en mangosta, pero no fue la solución.

    Intenté copiar en profundidad la instancia de mangosta ( http://blog.imaginea.com/deep-copy-in-javascript/ ) para pasar nuevas instancias de mangosta al subproyecto, pero arroja RangeError: Maximum call stack size exceeded.

Quiero saber, ¿hay alguna forma de usar múltiples bases de datos con mangosta o alguna solución para este problema? Porque creo que la mangosta es bastante fácil y rápida. ¿O algún otro módulo como recomendación?

pupot
fuente

Respuestas:

38

Una cosa que puede hacer es tener subcarpetas para cada proyecto. Entonces, instale mangosta en esas subcarpetas y requiera () mangosta de sus propias carpetas en cada sub-aplicaciones. No desde la raíz del proyecto ni desde global. Entonces, un subproyecto, una instalación de mangosta y una instancia de mangosta.

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

En foo_db_connect.js

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

En bar_db_connect.js

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

En archivos db_access.js

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

Ahora, puede acceder a múltiples bases de datos con mangosta.

tejo
fuente
2
Esto significa que cada proyecto tendrá su propia conexión. No podrá administrar 100k conexiones. Creo que sería mejor usar el useDbcomando que usa el mismo grupo de conexiones.
xpepermint
1
xpepermint, ¿puede mostrar un ejemplo para useDb? Tengo este problema actualmente stackoverflow.com/questions/37583198/…
Lion789
4
Esto parece una gran carga para el proyecto. no te parece?
Eshwar Prasad Yaddanapudi
1
Tener algunas instancias de conexión diferentes (por ejemplo, para una base de datos de usuario, una base de datos de sesión y para datos de aplicación) por aplicación está absolutamente bien. No es 'una gran carga' ni va a causar problemas de escalado y es un caso de uso común.
Iain Collins
¡Eres el mejor amigo mío! ¡muchas gracias! ¡esto funciona para mi! ¡Gracias!
Biruel Rick
214

De acuerdo con el manual fino , createConnection() se puede utilizar para conectarse a varias bases de datos.

Sin embargo, debe crear modelos separados para cada conexión / base de datos:

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

Estoy bastante seguro de que puede compartir el esquema entre ellos, pero debe verificarlo para asegurarse.

Robertklep
fuente
4
Sí, creo que las conexiones con nombre y un esquema compartido son el camino a seguir. Cada conexión necesitará un modelo único según el ejemplo de Robert.
Simon Holmes
21
También se encuentra useDb()disponible en 3.8 para compartir el grupo de conexiones subyacente: github.com/LearnBoost/mongoose/wiki/…
aaronheckmann
1
Supongamos que tengo una base de datos generada automáticamente (digamos n número de base de datos). Ni uno ni dos. ¿Hay alguna forma de conectarse a estos sin crear un modelo separado para cada base de datos?
Anooj Krishnan G
1
@AnoojKrishnanG No creo que eso sea posible, no. Necesita crear el modelo para cada base de datos por separado. Sin embargo, como ya dije en mi respuesta, es posible que pueda compartir el esquema entre las conexiones, lo que puede ahorrar algo de tiempo de codificación.
robertklep
1
Puede compartir el esquema entre los diferentes modelos y, por lo tanto, las bases de datos. var newSchema = new mongoose.Schema({ ... }), var model2 = conn1.model('newModel', newSchema),var model2 = conn2.model('newModel', newSchema)
conceder
42

Bastante tarde, pero esto podría ayudar a alguien. Las respuestas actuales asumen que está utilizando el mismo archivo para sus conexiones y modelos.

En la vida real, existe una alta probabilidad de que divida sus modelos en diferentes archivos. Puede usar algo como esto en su archivo 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 es exactamente como se describe en los documentos. Y luego, en sus archivos de modelo, haga algo como lo siguiente:

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;

Donde myDB es el nombre de su base de datos.

Tahnik Mustasin
fuente
Gracias, pude usar 3 bases de datos diferentes dentro de una sola aplicación usando: const mongoose = require ('mongoose'); const Schema = mongoose.Schema; const mySchema = nuevo esquema ({}); const mydbvar = mongoose.connection.useDb ('mydb') module.exports = mydbvar.model ('myCollection', MySchema);
Johnathan Enslin
2
Definitivamente el mejor y más real ejemplo del mundo. Conéctese a la base de datos predeterminada (como si estuviera usando algo como SQL Server) y luego aproveche useDb para apuntar su DML a la base de datos apropiada. (Muy útil para mantener a sus usuarios en una base de datos y sus datos en otra). No es necesario comenzar a realizar múltiples conexiones cuando, en última instancia, envía solicitudes al mismo servidor. Ahora, si se estuviera conectando a dos servidores diferentes, eso es una olla de pescado diferente.
Newclique
2
Como dijo @Wade, hasta donde tengo entendido, esta solución solo funciona cuando todas las bases de datos están en el mismo servidor. No está claro si esto responde a la pregunta del OP y la OMI es un poco engañosa.
Joniba
Esto es justo lo que necesitaba para la migración de MongoDB Atlas testy también para evitar tener múltiples conexiones. Sin embargo, también .dbal final ( const v1 = mongoose.connection.useDb('test').db), ya que la antigua base de datos no necesita ser administrada por mangosta.
Polv
37

Como enfoque alternativo, Mongoose exporta un constructor para una nueva instancia en la instancia predeterminada. Entonces, algo como esto es posible.

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

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

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

Esto es muy útil cuando se trabaja con fuentes de datos independientes y también cuando se desea tener un contexto de base de datos independiente para cada usuario o solicitud. Deberá tener cuidado, ya que es posible crear MUCHAS conexiones al hacer esto. Asegúrese de llamar a desconectar () cuando las instancias no sean necesarias y también de limitar el tamaño del grupo creado por cada instancia.

Eric
fuente
1
¿Es esta otra forma de escribir 'Respuesta anterior' ?
pravin
11
Esta no es la respuesta anterior, es mejor. La respuesta anterior instala varias copias de Mongoose, innecesariamente.
Martín Valdés de León
¿Cómo haría consultas con este método?
shahidfoy
2
await instance1.connection.collection('foo').insert({ foo: 'bar', }) await instance2.connection.collection('foo').insert({ foo: 'zoo', })
Abdallah Al Barmawi
De hecho funciona mejor en mi caso ya que tengo credenciales completamente diferentes para cada conexión, mucho menos modelos y bases de datos.
tzn
0

Una solución un poco optimizada (para mí al menos). escriba esto en un archivo db.js y solicítelo donde sea necesario y llámelo con una llamada de función y estará listo para comenzar.

   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
fuente