Mongoose i wiele baz danych w jednym projekcie node.js.

123

Robię projekt Node.js, który zawiera projekty podrzędne. Jeden podprojekt będzie miał jedną bazę danych Mongodb, a Mongoose będzie używany do pakowania i wysyłania zapytań do bazy danych. Ale problem w tym

  • Mongoose nie pozwala na używanie wielu baz danych w jednej instancji Mongoose, ponieważ modele są zbudowane na jednym połączeniu.
  • Aby użyć wielu instancji mongoose, Node.js nie zezwala na wiele instancji modułów, ponieważ ma system buforowania require(). Wiem, że wyłącz buforowanie modułów w Node.js, ale myślę, że nie jest to dobre rozwiązanie, ponieważ jest potrzebne tylko w przypadku mangusty.

    Próbowałem użyć createConnection()i openSet()w mangusty, ale to nie było rozwiązanie.

    Próbowałem głęboko skopiować instancję mangusty ( http://blog.imaginea.com/deep-copy-in-javascript/ ), aby przekazać nowe instancje mangusty do projektu podrzędnego, ale rzuca RangeError: Maximum call stack size exceeded.

Chcę wiedzieć, czy istnieje możliwość używania wielu baz danych z mangustą lub jakiegokolwiek obejścia tego problemu? Ponieważ uważam, że mangusta jest dość łatwa i szybka. Lub inne moduły jako zalecenia?

pupot
źródło

Odpowiedzi:

38

Jedną rzeczą, którą możesz zrobić, jest to, że możesz mieć podfoldery dla każdego projektu. Więc zainstaluj mongoose w tych podfolderach i wymagaj () mangusty z własnych folderów w każdej aplikacji podrzędnej. Nie z katalogu głównego projektu ani z pliku globalnego. Tak więc jeden podprojekt, jedna instalacja mongoose i jedna instancja 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/

W foo_db_connect.js

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

W bar_db_connect.js

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

W plikach db_access.js

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

Teraz możesz uzyskać dostęp do wielu baz danych za pomocą mangusty.

yemaw
źródło
2
Oznacza to, że każdy projekt będzie miał własne połączenie. Nie będziesz w stanie zarządzać 100 tys. Połączeń. Myślę, że byłoby lepiej użyć useDbpolecenia, które używa tej samej puli połączeń.
xpepermint
1
xpepermint, czy jesteś w stanie pokazać przykład dla useDb - mam obecnie ten problem stackoverflow.com/questions/37583198/ ...
Lion789
4
Wygląda to na ogromne obciążenie projektu. nie sądzisz?
Eshwar Prasad Yaddanapudi
1
Posiadanie kilku różnych instancji połączeń (np. Dla bazy danych użytkowników, bazy danych sesji i danych aplikacji) na aplikację jest całkowicie w porządku. Nie jest to „duże obciążenie” ani nie spowoduje problemów ze skalowaniem i jest częstym przypadkiem użycia.
Iain Collins,
Jesteś najlepszym przyjacielem! Dzięki wielkie! mi to pasuje! dzięki!
Biruel Rick
215

Zgodnie z drobną instrukcją , createConnection() może być używany do łączenia się z wieloma bazami danych.

Musisz jednak utworzyć osobne modele dla każdego połączenia / bazy danych:

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

Jestem prawie pewien, że możesz udostępniać schemat między nimi, ale musisz to sprawdzić, aby się upewnić.

robertklep
źródło
4
Tak, myślę, że nazwane połączenia i wspólny schemat są drogą do zrobienia. Każde połączenie będzie wymagało unikalnego modelu, jak na przykładzie Roberta.
Simon Holmes,
21
W useDb()wersji 3.8 dostępna jest również płatność
aaronheckmann
1
Załóżmy, że mam automatycznie wygenerowaną bazę danych (powiedz n numer bazy danych). Ani jednego, ani dwóch. Czy istnieje sposób na połączenie się z nimi bez tworzenia oddzielnego modelu dla każdej bazy danych?
Anooj Krishnan G
1
@AnoojKrishnanG Nie sądzę, żeby to było możliwe, nie. Musisz utworzyć model osobno dla każdej bazy danych. Jednak, jak już wspomniałem w mojej odpowiedzi, możesz być w stanie udostępnić schemat między połączeniami, co może zaoszczędzić trochę czasu na kodowaniu.
robertklep
1
Możesz udostępniać schemat w różnych modelach, a tym samym w DB. var newSchema = new mongoose.Schema({ ... }), var model2 = conn1.model('newModel', newSchema),var model2 = conn2.model('newModel', newSchema)
przyznanie
42

Dość późno, ale to może komuś pomóc. Obecne odpowiedzi zakładają, że używasz tego samego pliku dla połączeń i modeli.

W prawdziwym życiu istnieje duże prawdopodobieństwo, że podzielisz swoje modele na różne pliki. Możesz użyć czegoś takiego w swoim głównym pliku:

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

const db = mongoose.connection;

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

czyli właśnie tak jest to opisane w dokumentacji. A następnie w plikach modelu wykonaj coś takiego:

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;

Gdzie myDB to nazwa Twojej bazy danych.

Tahnik Mustasin
źródło
Dziękuję - mogłem użyć 3 różnych baz danych w ramach jednej aplikacji używając: const mongoose = require ('mongoose'); const Schema = mongoose.Schema; const mySchema = nowy schemat ({}); const mydbvar = mongoose.connection.useDb ('mydb') module.exports = mydbvar.model ('myCollection', MySchema);
Johnathan Enslin
2
Zdecydowanie najlepszy i najbardziej realny przykład. Połącz się z domyślną bazą danych (tak jak w przypadku używania czegoś takiego jak SQL Server), a następnie skorzystaj z useDb, aby skierować swój DML do odpowiedniej bazy danych. (Bardzo pomocne w utrzymywaniu użytkowników w jednej bazie danych, a danych w innej). Nie ma potrzeby nawiązywania wielu połączeń, gdy ostatecznie wysyłasz żądania do tego samego serwera. Teraz, jeśli łączysz się z dwoma różnymi serwerami, to jest inny kocioł rybny.
Newclique
2
Jak powiedział @Wade, o ile rozumiem, to rozwiązanie działa tylko wtedy, gdy wszystkie bazy danych znajdują się na tym samym serwerze. Nie jest jasne, czy to odpowiada na pytanie OP, a IMO jest nieco mylące.
joniba
To jest właśnie to, czego potrzebowałem do migracji MongoDB Atlas z test, a także do uniknięcia wielu połączeń. Jednak ja również .dbna końcu ( const v1 = mongoose.connection.useDb('test').db), ponieważ stara db nie musi być zarządzana mangustą.
Polv
37

Alternatywnie Mongoose eksportuje konstruktora dla nowej instancji w instancji domyślnej. Więc coś takiego jest możliwe.

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

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

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

Jest to bardzo przydatne podczas pracy z oddzielnymi źródłami danych, a także gdy chcesz mieć oddzielny kontekst bazy danych dla każdego użytkownika lub żądania. Będziesz musiał być ostrożny, ponieważ podczas wykonywania tej czynności można utworzyć DUŻO połączeń. Pamiętaj, aby wywołać rozłączenie (), gdy instancje nie są potrzebne, a także ograniczyć rozmiar puli tworzonej przez każdą instancję.

Eric
źródło
1
czy to inny sposób na napisanie „Powyżej odpowiedzi” ?
pravin
11
To nie jest powyższa odpowiedź, to lepiej. Powyższa odpowiedź niepotrzebnie instaluje wiele kopii Mongoose.
Martín Valdés de León
jak składałbym zapytania przy użyciu tej metody?
shahidfoy
2
await instance1.connection.collection('foo').insert({ foo: 'bar', }) await instance2.connection.collection('foo').insert({ foo: 'zoo', })
Abdallah Al Barmawi
W rzeczywistości lepiej działa w moim przypadku, ponieważ mam zupełnie inne poświadczenia dla każdego połączenia, nie mówiąc już o modelach i bazach danych.
tzn
0

Trochę zoptymalizowane (przynajmniej dla mnie) rozwiązanie. zapisz to do pliku db.js i zażądaj tego wszędzie tam, gdzie jest to wymagane, i wywołaj to za pomocą wywołania funkcji i jesteś gotowy.

   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
źródło