Mongoose và nhiều cơ sở dữ liệu trong dự án node.js duy nhất


123

Tôi đang thực hiện một dự án Node.js có chứa các dự án con. Một dự án con sẽ có một cơ sở dữ liệu Mongodb và Mongoose sẽ được sử dụng để gói và truy vấn db. Nhưng vấn đề là

  • Mongoose không cho phép sử dụng nhiều cơ sở dữ liệu trong một phiên bản mongoose duy nhất vì các mô hình được xây dựng trên một kết nối.
  • Để sử dụng nhiều phiên bản mongoose, Node.js không cho phép nhiều phiên bản mô-đun vì nó có hệ thống bộ nhớ đệm require(). Tôi biết vô hiệu hóa bộ nhớ đệm mô-đun trong Node.js nhưng tôi nghĩ đó không phải là giải pháp tốt vì nó chỉ cần mongoose.

    Tôi đã cố gắng sử dụng createConnection()openSet()trong mongoose, nhưng nó không phải là giải pháp.

    Tôi đã cố gắng sao chép sâu phiên bản mongoose ( http://blog.imaginea.com/deep-copy-in-javascript/ ) để chuyển các phiên bản mongoose mới vào dự án con, nhưng nó bị văng ra RangeError: Maximum call stack size exceeded.

Tôi muốn biết có cách nào để sử dụng nhiều cơ sở dữ liệu với mongoose hoặc bất kỳ giải pháp nào cho vấn đề này không? Vì mình nghĩ cầy mangut khá dễ và nhanh. Hoặc bất kỳ mô-đun nào khác như khuyến nghị?

Câu trả lời:


38

Một điều bạn có thể làm là, bạn có thể có các thư mục con cho mỗi dự án. Vì vậy, hãy cài đặt mongoose trong các thư mục con đó và yêu cầu () mongoose từ các thư mục riêng trong mỗi ứng dụng con. Không phải từ gốc dự án hoặc từ toàn cầu. Vì vậy, một dự án con, một cài đặt mongoose và một phiên bản 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/

Trong foo_db_connect.js

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

Trong bar_db_connect.js

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

Trong tệp db_access.js

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

Bây giờ, bạn có thể truy cập nhiều cơ sở dữ liệu với mongoose.


2
Điều này có nghĩa là mọi dự án sẽ có kết nối riêng của nó. Bạn sẽ không thể quản lý 100k kết nối. Tôi nghĩ sẽ tốt hơn nếu sử dụng useDblệnh sử dụng cùng một nhóm kết nối.
xpepermint

1
xpepermint là bạn có thể hiển thị một ví dụ cho useDb - Tôi gặp vấn đề này hiện stackoverflow.com/questions/37583198/...
Lion789

4
Điều này trông giống như một gánh nặng lớn cho dự án. bạn có nghĩ vậy không
Eshwar Prasad Yaddanapudi

1
Có một vài trường hợp kết nối khác nhau (ví dụ: đối với DB người dùng, DB phiên và dữ liệu ứng dụng) cho mỗi ứng dụng là hoàn toàn tốt. Nó không phải là 'một gánh nặng lớn' hoặc sẽ gây ra các vấn đề về quy mô và là một trường hợp sử dụng phổ biến.
Iain Collins

Bạn là người bạn tốt nhất của tôi! cám ơn rất nhiều! nó hoạt động cho tôi! cảm ơn!
Biruel Rick

214

Theo hướng dẫn sử dụng tốt , createConnection() có thể được sử dụng để kết nối với nhiều cơ sở dữ liệu.

Tuy nhiên, bạn cần tạo các mô hình riêng biệt cho từng kết nối / cơ sở dữ liệu:

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

Tôi khá chắc rằng bạn có thể chia sẻ lược đồ giữa chúng, nhưng bạn phải kiểm tra để đảm bảo.


4
Vâng, tôi nghĩ rằng các kết nối được đặt tên và một lược đồ dùng chung là cách để đi. Mỗi kết nối sẽ cần một mô hình duy nhất theo ví dụ của Robert.
Simon Holmes

21
Cũng useDb()có thể thanh toán vào ngày 3.8 để chia sẻ nhóm kết nối cơ bản: github.com/LearnBoost/mongoose/wiki/…
aaronheckmann

1
Giả sử tôi có cơ sở dữ liệu được tạo tự động (Giả sử số lượng cơ sở dữ liệu n). Không phải một hoặc hai. Có cách nào để kết nối với những thứ này mà không cần tạo mô hình riêng cho từng cơ sở dữ liệu không?
Anooj Krishnan G

1
@AnoojKrishnanG Tôi không nghĩ điều đó có thể, không. Bạn cần tạo mô hình dựa trên từng cơ sở dữ liệu riêng biệt. Tuy nhiên, như tôi đã nêu trong câu trả lời của mình, bạn có thể chia sẻ lược đồ giữa các kết nối, điều này có thể tiết kiệm một số thời gian viết mã.
robertklep

1
Bạn có thể chia sẻ lược đồ trên các mô hình khác nhau và do đó là các DB. var newSchema = new mongoose.Schema({ ... }), var model2 = conn1.model('newModel', newSchema),var model2 = conn2.model('newModel', newSchema)
cấp

42

Khá muộn nhưng điều này có thể giúp ích cho ai đó. Các câu trả lời hiện tại giả định rằng bạn đang sử dụng cùng một tệp cho các kết nối và mô hình của mình.

Trong cuộc sống thực, rất có thể bạn đang chia các mô hình của mình thành các tệp khác nhau. Bạn có thể sử dụng một cái gì đó như thế này trong tệp chính của mình:

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

const db = mongoose.connection;

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

đó chỉ là cách nó được mô tả trong tài liệu. Và sau đó trong các tệp mô hình của bạn, hãy làm như sau:

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;

Trong đó myDB là tên cơ sở dữ liệu của bạn.


Cảm ơn bạn - Tôi đã có thể sử dụng 3 cơ sở dữ liệu khác nhau trong một ứng dụng duy nhất bằng cách sử dụng: const mongoose = Requi ('mongoose'); const Schema = mongoose.Schema; const mySchema = new Schema ({}); const mydbvar = mongoose.connection.useDb ('mydb') module.exports = mydbvar.model ('myCollection', MySchema);
Johnathan Enslin

2
Chắc chắn là ví dụ tốt nhất và thực tế nhất. Kết nối với db mặc định (giống như nếu bạn đang sử dụng thứ gì đó như SQL Server) và sau đó tận dụng useDb để nhắm mục tiêu DML của bạn tại cơ sở dữ liệu thích hợp. (Rất hữu ích để giữ cho người dùng của bạn ở một db và dữ liệu của bạn ở một db khác.) Không cần phải bắt đầu tạo nhiều kết nối khi cuối cùng bạn đang gửi yêu cầu đến cùng một máy chủ. Bây giờ, nếu bạn đang kết nối với hai máy chủ khác nhau, đó là một ấm cá khác.
Newclique

2
Như @Wade đã nói, theo như tôi hiểu thì giải pháp này chỉ hoạt động khi tất cả các cơ sở dữ liệu nằm trên cùng một máy chủ. Không rõ liệu điều này có trả lời câu hỏi của OP hay không và IMO có một chút sai lệch.
joniba

Đây chỉ là những gì tôi cần cho quá trình di chuyển MongoDB Atlas từ đó testvà cũng để tránh có nhiều kết nối. Tuy nhiên, tôi cũng .dbở cuối ( const v1 = mongoose.connection.useDb('test').db) vì db cũ không cần được quản lý mongoose.
Polv

37

Là một phương pháp thay thế, Mongoose xuất một hàm tạo cho một phiên bản mới trên phiên bản mặc định. Vì vậy, một cái gì đó như thế này là có thể.

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

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

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

Điều này rất hữu ích khi làm việc với các nguồn dữ liệu riêng biệt và cũng như khi bạn muốn có ngữ cảnh cơ sở dữ liệu riêng cho từng người dùng hoặc yêu cầu. Bạn sẽ cần phải cẩn thận, vì có thể tạo ra RẤT NHIỀU kết nối khi thực hiện việc này. Đảm bảo gọi ngắt kết nối () khi các cá thể không cần thiết và cũng để giới hạn kích thước nhóm được tạo bởi mỗi cá thể.


1
Đây có phải là một cách khác để viết 'Câu trả lời trên' ?
pravin

11
Đây không phải là câu trả lời ở trên, nó tốt hơn. Câu trả lời trên cài đặt nhiều bản sao của Mongoose, không cần thiết.
Martín Valdés de León

tôi sẽ thực hiện các truy vấn bằng phương pháp này như thế nào?
shahidfoy

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

Trên thực tế, hoạt động tốt hơn trong trường hợp của tôi vì tôi có thông tin đăng nhập hoàn toàn khác nhau cho mỗi kết nối, chưa nói đến các mô hình và cơ sở dữ liệu.
tzn

0

Một giải pháp tối ưu hóa một chút (đối với tôi ít nhất). ghi nó vào một tệp db.js và yêu cầu nó ở bất cứ nơi nào cần thiết và gọi nó bằng một lệnh gọi hàm và bạn đã sẵn sàng.

   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;
    };
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.