Mongoose et plusieurs bases de données dans un seul projet node.js


123

Je fais un projet Node.js qui contient des sous-projets. Un sous-projet aura une base de données Mongodb et Mongoose sera utilisé pour encapsuler et interroger db. Mais le problème est

  • Mongoose ne permet pas d'utiliser plusieurs bases de données dans une seule instance de mangouste car les modèles sont construits sur une seule connexion.
  • Pour utiliser plusieurs instances de mangouste, Node.js n'autorise pas plusieurs instances de module car il dispose d'un système de mise en cache require(). Je sais désactiver la mise en cache du module dans Node.js mais je pense que ce n'est pas la bonne solution car il ne s'agit que de mangouste.

    J'ai essayé d'utiliser createConnection()et openSet()en mangouste, mais ce n'était pas la solution.

    J'ai essayé de copier en profondeur l'instance de mangouste ( http://blog.imaginea.com/deep-copy-in-javascript/ ) pour transmettre de nouvelles instances de mangouste au sous-projet, mais cela lance RangeError: Maximum call stack size exceeded.

Je veux savoir est-il possible d'utiliser plusieurs bases de données avec mangouste ou une solution de contournement pour ce problème? Parce que je pense que la mangouste est assez facile et rapide. Ou d'autres modules comme recommandations?

Réponses:


38

Une chose que vous pouvez faire est que vous pourriez avoir des sous-dossiers pour chaque projet. Donc, installez mongoose dans ces sous-dossiers et require () mongoose à partir de ses propres dossiers dans chaque sous-application. Pas à partir de la racine du projet ou de global. Donc un sous-projet, une installation mangouste et une instance mangouste.

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

Dans foo_db_connect.js

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

Dans bar_db_connect.js

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

Dans les fichiers db_access.js

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

Désormais, vous pouvez accéder à plusieurs bases de données avec mangouste.


2
Cela signifie que chaque projet aura sa propre connexion. Vous ne pourrez pas gérer 100 000 connexions. Je pense qu'il serait préférable d'utiliser la useDbcommande qui utilise le même pool de connexion.
xpepermint

1
xpepermint pouvez-vous montrer un exemple pour useDb - J'ai ce problème actuellement stackoverflow.com/questions/37583198
...

4
Cela ressemble à un énorme fardeau pour le projet. tu ne penses pas?
Eshwar Prasad Yaddanapudi

1
Avoir quelques instances de connexion différentes (par exemple pour une base de données utilisateur, une base de données de session et pour les données d'application) par application est tout à fait acceptable. Ce n'est pas «un énorme fardeau» ou ne va pas causer de problèmes de mise à l'échelle et c'est un cas d'utilisation courant.
Iain Collins

Tu es le meilleur mon ami! Merci beaucoup! ça marche pour moi! Merci!
Biruel Rick

214

Selon le manuel fin , createConnection() peut être utilisé pour se connecter à plusieurs bases de données.

Cependant, vous devez créer des modèles distincts pour chaque connexion / base de données:

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

Je suis presque sûr que vous pouvez partager le schéma entre eux, mais vous devez vérifier pour vous en assurer.


4
Oui, je pense que les connexions nommées et un schéma partagé sont la voie à suivre. Chaque connexion aura besoin d'un modèle unique selon l'exemple de Robert.
Simon Holmes

21
Également useDb()disponible dans la version 3.8 pour partager le pool de connexions sous-jacent: github.com/LearnBoost/mongoose/wiki/…
aaronheckmann

1
Supposons que j'ai une base de données générée automatiquement (dites n nombre de base de données). Pas un ou deux. Existe-t-il un moyen de s'y connecter sans créer de modèle distinct pour chaque base de données?
Anooj Krishnan G

1
@AnoojKrishnanG Je ne pense pas que ce soit possible, non. Vous devez créer le modèle par rapport à chaque base de données séparément. Cependant, comme je l'ai déjà dit dans ma réponse, vous pourrez peut-être partager le schéma entre les connexions, ce qui peut gagner du temps de codage.
robertklep

1
Vous pouvez partager le schéma entre les différents modèles, et donc les bases de données. var newSchema = new mongoose.Schema({ ... }), var model2 = conn1.model('newModel', newSchema),var model2 = conn2.model('newModel', newSchema)
accorder

42

Assez tard mais cela pourrait aider quelqu'un. Les réponses actuelles supposent que vous utilisez le même fichier pour vos connexions et modèles.

Dans la vraie vie, il y a de fortes chances que vous divisiez vos modèles en différents fichiers. Vous pouvez utiliser quelque chose comme ceci dans votre fichier 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');
});

ce qui est juste comme cela est décrit dans la documentation. Et puis dans vos fichiers de modèle, faites quelque chose comme ceci:

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;

Où myDB est le nom de votre base de données.


Merci - J'ai pu utiliser 3 bases de données différentes dans une seule application en utilisant: const mongoose = require ('mongoose'); const Schema = mangouste.Schema; const mySchema = nouveau schéma ({}); const mydbvar = mongoose.connection.useDb ('mydb') module.exports = mydbvar.model ('myCollection', MySchema);
Johnathan Enslin

2
Certainement le meilleur exemple et le plus réel. Connectez-vous à la base de données par défaut (comme si vous utilisiez quelque chose comme SQL Server), puis profitez de useDb pour cibler votre DML sur la base de données appropriée. (Très utile pour garder vos utilisateurs dans une base de données et vos données dans une autre.) Pas besoin de commencer à établir plusieurs connexions lorsque vous envoyez des requêtes au même serveur. Maintenant, si vous vous connectez à deux serveurs différents, c'est une marmite de poisson différente.
Newclique

2
Comme l'a dit @Wade, pour autant que je sache, cette solution ne fonctionne que lorsque toutes les bases de données sont sur le même serveur. Il n'est pas clair si cela répond à la question du PO et l'OMI est un peu trompeuse.
joniba

C'est exactement ce dont j'avais besoin pour la migration de MongoDB Atlas à partir de test, et aussi pour éviter d'avoir plusieurs connexions. Cependant, j'ai aussi .dbà la fin ( const v1 = mongoose.connection.useDb('test').db) car l'ancienne base de données n'a pas besoin d'être gérée par mangouste.
Polv

37

Comme approche alternative, Mongoose exporte un constructeur pour une nouvelle instance sur l'instance par défaut. Donc, quelque chose comme ça est possible.

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

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

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

Ceci est très utile lorsque vous travaillez avec des sources de données distinctes, et également lorsque vous souhaitez avoir un contexte de base de données distinct pour chaque utilisateur ou requête. Vous devrez faire attention, car il est possible de créer BEAUCOUP de connexions en faisant cela. Assurez-vous d'appeler disconnect () lorsque les instances ne sont pas nécessaires, et également de limiter la taille du pool créé par chaque instance.


1
est-ce une autre façon d'écrire «Au-dessus de la réponse» ?
pravin

11
Ce n'est pas la réponse ci-dessus, c'est mieux. La réponse ci-dessus installe plusieurs copies de Mongoose, inutilement.
Martín Valdés de León

comment puis-je faire des requêtes en utilisant cette méthode?
shahidfoy

2
await instance1.connection.collection('foo').insert({ foo: 'bar', }) await instance2.connection.collection('foo').insert({ foo: 'zoo', })
Abdallah Al Barmawi le

En fait, cela fonctionne mieux dans mon cas car j'ai des informations d'identification complètement différentes pour chaque connexion, sans parler des modèles et des bases de données.
tzn

0

Une solution un peu optimisée (pour moi au moins). écrivez ceci dans un fichier db.js et exigez-le partout où c'est nécessaire et appelez-le avec un appel de fonction et vous êtes prêt à partir.

   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;
    };
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.