พังพอนและฐานข้อมูลจำนวนมากในโครงการ node.js เดียว


123

ฉันกำลังทำโปรเจ็กต์ Node.js ที่มีโปรเจ็กต์ย่อย โครงการย่อยหนึ่งโครงการจะมีฐานข้อมูล Mongodb หนึ่งฐานข้อมูลและ Mongoose จะใช้สำหรับการตัดและการสืบค้นฐานข้อมูล แต่ปัญหาคือ

  • พังพอนไม่อนุญาตให้ใช้หลายฐานข้อมูลในอินสแตนซ์พังพอนเดียวเนื่องจากแบบจำลองสร้างจากการเชื่อมต่อเดียว
  • ในการใช้อินสแตนซ์พังพอนหลาย Node.js require()ไม่อนุญาตให้อินสแตนซ์โมดูลหลายอย่างที่มันมีระบบแคชใน ฉันรู้ว่าปิดการใช้งานการแคชโมดูลใน Node.js แต่ฉันคิดว่ามันไม่ใช่ทางออกที่ดีเพราะมันจำเป็นสำหรับพังพอนเท่านั้น

    ฉันพยายามใช้createConnection()และopenSet()พังพอน แต่มันไม่ใช่วิธีแก้ปัญหา

    ผมได้พยายามที่จะคัดลอกลึกเช่นพังพอน ( http://blog.imaginea.com/deep-copy-in-javascript/ ) จะผ่านอินสแตนซ์พังพอนใหม่กับโครงการย่อย RangeError: Maximum call stack size exceededแต่ก็ขว้างปา

ฉันต้องการทราบว่ามีวิธีใดบ้างที่จะใช้ฐานข้อมูลหลายฐานข้อมูลกับพังพอนหรือวิธีแก้ปัญหาใด ๆ สำหรับปัญหานี้ เพราะฉันคิดว่าพังพอนค่อนข้างง่ายและรวดเร็ว หรือโมดูลอื่น ๆ ตามคำแนะนำ?

คำตอบ:


38

สิ่งหนึ่งที่คุณทำได้คือคุณอาจมีโฟลเดอร์ย่อยสำหรับแต่ละโครงการ ดังนั้นให้ติดตั้งพังพอนในโฟลเดอร์ย่อยนั้นและต้องการพังพอน () พังพอนจากโฟลเดอร์ของตัวเองในแต่ละแอปพลิเคชันย่อย ไม่ใช่จากรากของโครงการหรือจากทั่วโลก ดังนั้นหนึ่งโครงการย่อยการติดตั้งพังพอนหนึ่งตัวและหนึ่งอินสแตนซ์พังพอน

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

ใน foo_db_connect.js

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

ใน bar_db_connect.js

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

ในไฟล์ db_access.js

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

ตอนนี้คุณสามารถเข้าถึงฐานข้อมูลหลายแห่งด้วยพังพอน


2
นั่นหมายความว่าทุกโครงการจะมีการเชื่อมต่อของตัวเอง คุณจะไม่สามารถจัดการการเชื่อมต่อ 100k ได้ ฉันคิดว่ามันจะดีกว่าถ้าใช้useDbคำสั่งที่ใช้พูลการเชื่อมต่อเดียวกัน
xpepermint

1
xpepermint คุณสามารถแสดงตัวอย่างสำหรับ useDb ได้หรือไม่ - ฉันมีปัญหานี้ในขณะนี้stackoverflow.com/questions/37583198/…
Lion789

4
ดูเหมือนว่าจะเป็นภาระอย่างมากในโครงการ คุณไม่คิดอย่างนั้นเหรอ?
Eshwar Prasad Yaddanapudi

1
การมีอินสแตนซ์การเชื่อมต่อที่แตกต่างกันเล็กน้อย (เช่นสำหรับ User DB, Session DB และสำหรับข้อมูลแอปพลิเคชัน) ต่อแอปพลิเคชันนั้นดีมาก ไม่ใช่ 'ภาระใหญ่' หรือก่อให้เกิดปัญหาการปรับขนาดและเป็นกรณีการใช้งานทั่วไป
Iain Collins

คุณเป็นเพื่อนที่ดีที่สุดของฉัน! ขอบคุณมาก! มันได้ผลสำหรับฉัน! ขอบคุณ!
Biruel Rick

215

ตามคู่มือที่ดี , createConnection() สามารถนำมาใช้เพื่อเชื่อมต่อกับฐานข้อมูลหลาย

อย่างไรก็ตามคุณต้องสร้างแบบจำลองแยกต่างหากสำหรับการเชื่อมต่อ / ฐานข้อมูลแต่ละรายการ:

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

ฉันค่อนข้างมั่นใจว่าคุณสามารถแชร์สคีมาระหว่างกันได้ แต่คุณต้องตรวจสอบให้แน่ใจ


4
ใช่การเชื่อมต่อที่มีชื่อและสคีมาที่ใช้ร่วมกันเป็นวิธีที่ฉันคิดว่า การเชื่อมต่อแต่ละครั้งจะต้องมีรูปแบบเฉพาะตามตัวอย่างของ Robert
Simon Holmes

21
นอกจากนี้ยังมีการชำระเงินuseDb()ใน 3.8 เพื่อแชร์พูลการเชื่อมต่อพื้นฐาน: github.com/LearnBoost/mongoose/wiki/…
aaronheckmann

1
สมมติว่าฉันมีฐานข้อมูลที่สร้างขึ้นโดยอัตโนมัติ (พูด n จำนวนฐานข้อมูล) ไม่ใช่หนึ่งหรือสอง มีวิธีใดบ้างในการเชื่อมต่อกับสิ่งเหล่านี้โดยไม่ต้องสร้างโมเดลแยกต่างหากสำหรับแต่ละฐานข้อมูล
Anooj Krishnan G

1
@AnoojKrishnanG ฉันไม่คิดว่าจะเป็นไปได้ คุณต้องสร้างโมเดลกับแต่ละฐานข้อมูลแยกกัน อย่างไรก็ตามตามที่ฉันได้ระบุไว้ในคำตอบของฉันคุณอาจสามารถแบ่งปันสคีมาระหว่างการเชื่อมต่อซึ่งอาจช่วยประหยัดเวลาในการเขียนโค้ดได้บ้าง
robertklep

1
คุณสามารถแชร์สคีมาในรูปแบบต่างๆและดังนั้นฐานข้อมูล var newSchema = new mongoose.Schema({ ... }), var model2 = conn1.model('newModel', newSchema),var model2 = conn2.model('newModel', newSchema)
ให้

42

ค่อนข้างช้า แต่อาจช่วยใครบางคนได้ คำตอบปัจจุบันจะถือว่าคุณใช้ไฟล์เดียวกันสำหรับการเชื่อมต่อและโมเดลของคุณ

ในชีวิตจริงมีโอกาสสูงที่คุณจะแยกโมเดลออกเป็นไฟล์ต่างๆ คุณสามารถใช้สิ่งนี้ในไฟล์หลักของคุณ:

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

const db = mongoose.connection;

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

ซึ่งเป็นเพียงวิธีที่อธิบายไว้ในเอกสาร จากนั้นในไฟล์โมเดลของคุณให้ทำสิ่งต่อไปนี้:

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;

โดย myDB คือชื่อฐานข้อมูลของคุณ


ขอบคุณ - ฉันสามารถใช้ฐานข้อมูลที่แตกต่างกัน 3 ฐานข้อมูลภายในแอปพลิเคชั่นเดียวโดยใช้: const mongoose = ต้องใช้ ('พังพอน'); const Schema = พังพอนสคีมา; const mySchema = สคีมาใหม่ ({}); const mydbvar = mongoose.connection.useDb ('mydb') module.exports = mydbvar.model ('myCollection', MySchema);
Johnathan Enslin

2
เป็นตัวอย่างที่ดีที่สุดและเป็นจริงที่สุด เชื่อมต่อกับ db เริ่มต้น (เช่นเดียวกับที่คุณใช้บางอย่างเช่น SQL Server) จากนั้นใช้ประโยชน์จาก useDb เพื่อกำหนดเป้าหมาย DML ของคุณที่ฐานข้อมูลที่เหมาะสม (มีประโยชน์มากในการรักษาผู้ใช้ของคุณไว้ในฐานข้อมูลเดียวและข้อมูลของคุณในอีกฐานข้อมูลหนึ่ง) ไม่จำเป็นต้องเริ่มทำการเชื่อมต่อหลายรายการเมื่อคุณส่งคำขอไปยังเซิร์ฟเวอร์เดียวกันในที่สุด ตอนนี้ถ้าคุณเชื่อมต่อกับเซิร์ฟเวอร์ที่แตกต่างกันสองเครื่องนั่นคือกาต้มน้ำปลาที่แตกต่างกัน
Newclique

2
ดังที่ @Wade กล่าวเท่าที่ฉันเข้าใจวิธีนี้ใช้งานได้ก็ต่อเมื่อฐานข้อมูลทั้งหมดอยู่บนเซิร์ฟเวอร์เดียวกัน ยังไม่ชัดเจนว่าสิ่งนี้ตอบคำถามของ OP หรือไม่และ IMO นั้นทำให้เข้าใจผิดเล็กน้อย
joniba

นี่เป็นเพียงสิ่งที่ฉันต้องการสำหรับการย้าย MongoDB Atlas testและเพื่อหลีกเลี่ยงการเชื่อมต่อหลายครั้ง แต่ผมยัง.dbที่สิ้นสุด ( const v1 = mongoose.connection.useDb('test').db) เป็นฐานข้อมูลเก่าไม่จำเป็นต้องได้รับการจัดการพังพอน
Polv

37

อีกวิธีหนึ่งคือ Mongoose ส่งออกคอนสตรัคเตอร์สำหรับอินสแตนซ์ใหม่บนอินสแตนซ์เริ่มต้น สิ่งนี้จึงเป็นไปได้

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

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

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

สิ่งนี้มีประโยชน์มากเมื่อทำงานกับแหล่งข้อมูลที่แยกจากกันและเมื่อคุณต้องการมีบริบทฐานข้อมูลแยกต่างหากสำหรับผู้ใช้หรือคำขอแต่ละรายการ คุณจะต้องระมัดระวังเนื่องจากเป็นไปได้ที่จะสร้างการเชื่อมต่อจำนวนมากเมื่อทำสิ่งนี้ อย่าลืมโทรยกเลิกการเชื่อมต่อ () เมื่อไม่ต้องการอินสแตนซ์และ จำกัด ขนาดพูลที่สร้างโดยแต่ละอินสแตนซ์


1
นี่เป็นอีกวิธีหนึ่งในการเขียน'คำตอบข้างต้น'หรือไม่?
pravin

11
นี่ไม่ใช่คำตอบข้างบนจะดีกว่า คำตอบข้างต้นติดตั้งพังพอนหลายสำเนาโดยไม่จำเป็น
MartínValdés de León

ฉันจะทำแบบสอบถามโดยใช้วิธีนี้ได้อย่างไร
shahidfoy

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

ในความเป็นจริงทำงานได้ดีขึ้นในกรณีของฉันเนื่องจากฉันมีข้อมูลประจำตัวที่แตกต่างกันอย่างสิ้นเชิงสำหรับการเชื่อมต่อแต่ละครั้งนับประสาโมเดลและฐานข้อมูล
tzn

0

โซลูชันที่ปรับให้เหมาะสมที่สุด (สำหรับฉันอย่างน้อยที่สุด) เขียนสิ่งนี้ลงในไฟล์ db.js และต้องการสิ่งนี้ในทุกที่ที่ต้องการและเรียกมันด้วยการเรียกใช้ฟังก์ชันและคุณก็พร้อมที่จะไป

   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;
    };
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.