मैं एक Node.js वेब एप्लिकेशन में MongoDB कनेक्शन कैसे प्रबंधित करूं?


288

मैं एक वेबसाइट लिखने के लिए MongoDB के साथ नोड-मोंगोडब-देशी ड्राइवर का उपयोग कर रहा हूं ।

कनेक्शन प्रबंधित करने के तरीके के बारे में मेरे कुछ सवाल हैं:

  1. क्या यह सभी अनुरोधों के लिए केवल एक MongoDB कनेक्शन का उपयोग करने के लिए पर्याप्त है? क्या कोई प्रदर्शन मुद्दे हैं? यदि नहीं, तो क्या मैं पूरे एप्लिकेशन में उपयोग के लिए एक वैश्विक कनेक्शन सेटअप कर सकता हूं?

  2. यदि नहीं, तो क्या यह अच्छा है यदि मैं अनुरोध आने पर एक नया कनेक्शन खोलता हूं, और अनुरोध को संभालने के बाद इसे बंद कर देता हूं? क्या कनेक्शन खोलना और बंद करना महंगा है?

  3. क्या मुझे वैश्विक कनेक्शन पूल का उपयोग करना चाहिए? मैंने सुना है ड्राइवर का एक देशी कनेक्शन पूल है। क्या यह एक अच्छा विकल्प है?

  4. यदि मैं एक कनेक्शन पूल का उपयोग करता हूं, तो कितने कनेक्शन का उपयोग किया जाना चाहिए?

  5. क्या अन्य चीजें हैं जिन्हें मुझे नोटिस करना चाहिए?


@ IonicãBizãu, क्षमा करें, मैंने लंबे समय तक नोडज का उपयोग नहीं किया है जो मैंने इसे नहीं देखा है। आपकी टिप्पणी के लिए धन्यवाद ~
Freewind

जवाबों:


459

नोड-मोंगोडब-मूल के प्राथमिक कमिटर कहते हैं :

जब आपका ऐप बूट हो जाए और db ऑब्जेक्ट का पुनः उपयोग करे तो आप एक बार MongoClient.connect को खोलें। यह एक सिंगलटन कनेक्शन पूल नहीं है। प्रत्येक एक नया कनेक्शन पूल बनाता है।

इसलिए, अपने प्रश्न का सीधे उत्तर देने के लिए, उस db ऑब्जेक्ट का पुन: उपयोग करेंMongoClient.connect() , जिसके परिणाम हैं । यह आपको पूलिंग प्रदान करता है, और प्रत्येक db क्रिया पर कनेक्शन खोलने / बंद करने की तुलना में एक ध्यान देने योग्य गति में वृद्धि प्रदान करेगा।



4
यह सही जवाब है। स्वीकृत उत्तर बहुत गलत है क्योंकि यह प्रत्येक अनुरोध के लिए एक कनेक्शन पूल खोलने के लिए कहता है और ऐसा करने के बाद इसे बंद कर देता है। भयानक वास्तुकला।
सरसंघ महापात्र

7
यह एक सही उत्तर है। मेरे भगवान कल्पना करते हैं कि मुझे हर बार खोलना और बंद करना पड़ता है जब मैं कुछ करता हूँ तो यह मेरी आवेषण के लिए प्रति घंटे 350K होगा! यह मेरे अपने सर्वर पर हमला करने जैसा है।
माज़ियार

1
@ क्रैकर: यदि आपके पास एक्सप्रेस एप्लिकेशन है, तो आप db ऑब्जेक्ट को req.dbइस मिडलवेयर में सेव कर सकते हैं : github.com/floatdrop/express-mongo-db
floatdrop

1
अगर एक से अधिक डेटाबेस हैं .. तो क्या मुझे एक साथ प्रत्येक डेटाबेस के लिए एक कनेक्शन खोलना चाहिए। यदि नहीं, तो क्या आवश्यक होने पर इसे खोलना और बंद करना ठीक है?
अमन गुप्ता

45

Node.js एप्लिकेशन शुरू होने पर एक नया कनेक्शन खोलें, और मौजूदा dbकनेक्शन ऑब्जेक्ट का पुन: उपयोग करें :

/server.js

import express from 'express';
import Promise from 'bluebird';
import logger from 'winston';
import { MongoClient } from 'mongodb';
import config from './config';
import usersRestApi from './api/users';

const app = express();

app.use('/api/users', usersRestApi);

app.get('/', (req, res) => {
  res.send('Hello World');
});

// Create a MongoDB connection pool and start the application
// after the database connection is ready
MongoClient.connect(config.database.url, { promiseLibrary: Promise }, (err, db) => {
  if (err) {
    logger.warn(`Failed to connect to the database. ${err.stack}`);
  }
  app.locals.db = db;
  app.listen(config.port, () => {
    logger.info(`Node.js app is listening at http://localhost:${config.port}`);
  });
});

/api/users.js

import { Router } from 'express';
import { ObjectID } from 'mongodb';

const router = new Router();

router.get('/:id', async (req, res, next) => {
  try {
    const db = req.app.locals.db;
    const id = new ObjectID(req.params.id);
    const user = await db.collection('user').findOne({ _id: id }, {
      email: 1,
      firstName: 1,
      lastName: 1
    });

    if (user) {
      user.id = req.params.id;
      res.send(user);
    } else {
      res.sendStatus(404);
    }
  } catch (err) {
    next(err);
  }
});

export default router;

स्रोत: Node.js / एक्सप्रेस ऐप में डेटाबेस कनेक्शन कैसे खोलें


1
यह एक डेटाबेस कनेक्शन बनाता है ... यदि आप पूल का उपयोग करना चाहते हैं, तो आपको प्रत्येक उपयोग पर / बंद करना होगा
amcdnl

15
ऑफ-टॉपिक, यह सबसे अजीब NodeJS फाइल है जिसे मैंने कभी देखा है।
हॉबीस्ट

1
पहले कभी app.locals के बारे में नहीं सुना, लेकिन मुझे खुशी है कि आपने मुझे उनके साथ यहां पेश किया
Z_z_Z

1
मेरी बहुत मदद की! मैं हर अनुरोध के लिए डीबी कनेक्शन बनाने / बंद करने की गलती करता हूं, मेरे ऐप का परफॉमेंस इसके साथ नीचे गिर गया।
लिएंड्रो लीमा

18

यहाँ कुछ कोड है जो आपके MongoDB कनेक्शन को प्रबंधित करेगा।

var MongoClient = require('mongodb').MongoClient;
var url = require("../config.json")["MongoDBURL"]

var option = {
  db:{
    numberOfRetries : 5
  },
  server: {
    auto_reconnect: true,
    poolSize : 40,
    socketOptions: {
        connectTimeoutMS: 500
    }
  },
  replSet: {},
  mongos: {}
};

function MongoPool(){}

var p_db;

function initPool(cb){
  MongoClient.connect(url, option, function(err, db) {
    if (err) throw err;

    p_db = db;
    if(cb && typeof(cb) == 'function')
        cb(p_db);
  });
  return MongoPool;
}

MongoPool.initPool = initPool;

function getInstance(cb){
  if(!p_db){
    initPool(cb)
  }
  else{
    if(cb && typeof(cb) == 'function')
      cb(p_db);
  }
}
MongoPool.getInstance = getInstance;

module.exports = MongoPool;

जब आप सर्वर शुरू करते हैं, तो कॉल करें initPool

require("mongo-pool").initPool();

फिर किसी अन्य मॉड्यूल में आप निम्न कार्य कर सकते हैं:

var MongoPool = require("mongo-pool");
MongoPool.getInstance(function (db){
    // Query your MongoDB database.
});

यह MongoDB प्रलेखन पर आधारित है । इस पर एक नज़र मारो।


3
5.x से अपडेट करें: var विकल्प = {numberOfRetries: 5, auto_reconnect: true, poolSize: 40, connectTimeoutMS: 30000};
ब्लेयर

15

एक एकल स्वयं के मॉड्यूल में मोंगो कनेक्शन पूल प्रबंधित करें। यह दृष्टिकोण दो लाभ प्रदान करता है। सबसे पहले यह आपके कोड को मॉड्यूलर और परीक्षण के लिए आसान रखता है। दूसरी बात यह है कि आपके डेटाबेस कनेक्शन को आपके अनुरोध ऑब्जेक्ट में मिलाने के लिए मजबूर नहीं किया जाता है जो डेटाबेस कनेक्शन ऑब्जेक्ट के लिए जगह नहीं है। (जावास्क्रिप्ट की प्रकृति को देखते हुए मैं पुस्तकालय कोड द्वारा निर्मित किसी भी वस्तु में किसी भी चीज को मिलाना बहुत खतरनाक समझूंगा)। तो इसके साथ आपको केवल एक मॉड्यूल पर विचार करने की आवश्यकता है जो दो तरीकों का निर्यात करता है। connect = () => Promiseऔर get = () => dbConnectionObject

इस तरह के एक मॉड्यूल के साथ आप सबसे पहले डेटाबेस से जुड़ सकते हैं

// runs in boot.js or what ever file your application starts with
const db = require('./myAwesomeDbModule');
db.connect()
    .then(() => console.log('database connected'))
    .then(() => bootMyApplication())
    .catch((e) => {
        console.error(e);
        // Always hard exit on a database connection error
        process.exit(1);
    });

जब उड़ान में आपका ऐप बस कॉल कर सकता है get()जब उसे डीबी कनेक्शन की आवश्यकता होती है।

const db = require('./myAwesomeDbModule');
db.get().find(...)... // I have excluded code here to keep the example  simple

यदि आप अपने डीबी मॉड्यूल को उसी तरह सेट करते हैं, तो न केवल निम्नलिखित के लिए आपके पास यह सुनिश्चित करने का एक तरीका होगा कि आपका आवेदन तब तक बूट नहीं होगा जब तक कि आपके पास एक डेटाबेस कनेक्शन न हो, आपके पास अपने डेटाबेस कनेक्शन पूल तक पहुंचने का एक वैश्विक तरीका है जो त्रुटि देगा अगर आपको कनेक्शन नहीं मिला है।

// myAwesomeDbModule.js
let connection = null;

module.exports.connect = () => new Promise((resolve, reject) => {
    MongoClient.connect(url, option, function(err, db) {
        if (err) { reject(err); return; };
        resolve(db);
        connection = db;
    });
});

module.exports.get = () => {
    if(!connection) {
        throw new Error('Call connect first!');
    }

    return connection;
}

बहुत उपयोगी है, वास्तव में मैं क्या देख रहा था!
अगुई

बेहतर अभी तक, आप कनेक्ट () फ़ंक्शन से छुटकारा पा सकते हैं और यह देखने के लिए कि क्या कनेक्शन है, यह देखने के लिए () फ़ंक्शन चेक करें और अगर यह है तो कनेक्ट करें। मिला है () हमेशा एक वादा वापस करो। यह है कि मैं अपने कनेक्शन को कैसे प्रबंधित करता हूं और यह बहुत अच्छा काम करता है। यह सिंगलटन पैटर्न का उपयोग है।
जावा-आदी ३०१

@ java-addict301 जबकि यह दृष्टिकोण एक अधिक सुव्यवस्थित एपीआई प्रदान करता है, जिसमें दो कमियां हैं। पहला यह है कि कनेक्शन त्रुटियों की जांच करने के लिए कोई परिभाषित तरीका नहीं है। जब आप कॉल करते हैं तो आपको उस इनलाइन को हर जगह संभालना होगा। मुझे डेटाबेस कनेक्शन के साथ जल्दी असफल होना पसंद है और आम तौर पर मैं ऐप को डेटाबेस से कनेक्शन के साथ बूट नहीं होने दूंगा। दूसरा मुद्दा थ्रूपुट है। क्योंकि आपके पास एक सक्रिय कनेक्शन नहीं है, इसलिए आपको पहले प्राप्त () कॉल पर थोड़ी देर इंतजार करना पड़ सकता है, जिस पर आपका नियंत्रण नहीं होगा। आपके रिपोर्टिंग मैट्रिक्स को तिरछा कर सकता है।
स्टीवर्ट

1
@Stewart जिस तरह से मैं एप्लिकेशन / सेवाओं को संरचना करता हूं, वह आमतौर पर स्टार्टअप पर डेटाबेस से एक कॉन्फ़िगरेशन को पुनः प्राप्त करना है। इस तरह, डेटाबेस के अप्राप्य होने पर एप्लिकेशन प्रारंभ करने में विफल हो जाएगा। इसके अलावा, क्योंकि पहला अनुरोध हमेशा स्टार्टअप पर होता है, इस डिजाइन के साथ मैट्रिक्स के साथ कोई समस्या नहीं है। साथ ही एक कनेक्शन अपवाद को एक बार में एकल में जगह के साथ एक अपवाद अपवाद को हटा दें, जिससे यह स्पष्ट त्रुटि नहीं हो सकती है। चूंकि एप्लिकेशन को वैसे भी कनेक्शन का उपयोग करते समय डेटाबेस त्रुटियों को पकड़ने की आवश्यकता होती है, इससे कोई अतिरिक्त इनलाइन हैंडलिंग नहीं होती है।
जावा-आदी ३०१

2
हाय @ अयान। यहां यह ध्यान रखना महत्वपूर्ण है कि जब हम कॉल get()करते हैं तो हमें एक कनेक्शन नहीं एक कनेक्शन पूल मिल रहा है। एक कनेक्शन पूल, जैसा कि नाम का तात्पर्य है डेटाबेस कनेक्शन का एक तार्किक संग्रह है। यदि पूल में कोई कनेक्शन नहीं हैं, तो ड्राइवर एक को खोलने का प्रयास करेगा। एक बार जब कनेक्शन खुला होता है तो इसका उपयोग किया जाता है और पूल में वापस आ जाता है। अगली बार जब पूल का उपयोग किया जाता है तो यह कनेक्शन पुन: उपयोग किया जा सकता है। यहाँ अच्छी बात यह है कि पूल हमारे लिए हमारे कनेक्शन का प्रबंधन करेगा, इसलिए यदि एक कनेक्शन गिरा दिया जाता है, तो हम कभी नहीं जान सकते हैं क्योंकि पूल हमारे लिए एक नया खोल देगा।
स्टीवर्ट

11

यदि आपके पास Express.js है, तो आप बिना किसी पूल के अनुरोधों के बीच MongoDB कनेक्शन को कैशिंग और साझा करने के लिए एक्सप्रेस-मोंगो-डीबी का उपयोग कर सकते हैं (चूंकि स्वीकृत उत्तर कहता है कि यह कनेक्शन साझा करने का सही तरीका है)।

यदि नहीं - आप इसके स्रोत कोड को देख सकते हैं और इसे किसी अन्य ढांचे में उपयोग कर सकते हैं।


6

मैं अपने ऐप में रेडिस कनेक्शन के साथ जेनेरिक-पूल का उपयोग कर रहा हूं - मैं इसकी अत्यधिक अनुशंसा करता हूं। इसके सामान्य और मुझे निश्चित रूप से पता है कि यह mysql के साथ काम करता है, इसलिए मुझे नहीं लगता कि आपको इसके और मोंगो के साथ कोई समस्या होगी

https://github.com/coopernurse/node-pool


Mongo पहले से ही ड्राइवर में कनेक्शन पूलिंग करता है, मेरे पास हालांकि मेरे mongo कनेक्शन को एक इंटरफ़ेस में मैप किया गया है जो नोड-पूल से मेल खाता है, इस तरह से मेरे सभी कनेक्शन समान पैटर्न का पालन करते हैं, भले ही mongo के मामले में, क्लीनअप नहीं करता है वास्तव में कुछ भी ट्रिगर।
ट्रैकर 1

4

आपको सेवा के रूप में एक कनेक्शन बनाना चाहिए फिर आवश्यकता होने पर इसका पुन: उपयोग करें।

// db.service.js
import { MongoClient } from "mongodb";
import database from "../config/database";

const dbService = {
  db: undefined,
  connect: callback => {
    MongoClient.connect(database.uri, function(err, data) {
      if (err) {
        MongoClient.close();
        callback(err);
      }
      dbService.db = data;
      console.log("Connected to database");
      callback(null);
    });
  }
};

export default dbService;

मेरा App.js नमूना

// App Start
dbService.connect(err => {
  if (err) {
    console.log("Error: ", err);
    process.exit(1);
  }

  server.listen(config.port, () => {
    console.log(`Api runnning at ${config.port}`);
  });
});

और जहाँ चाहो वहाँ इसका इस्तेमाल करो

import dbService from "db.service.js"
const db = dbService.db

1
यदि मोंगो कनेक्ट नहीं कर सका, MongoClient.close () एक त्रुटि देता है। लेकिन मूल समस्या के लिए एक अच्छा समाधान।
हिमांशु

3

http://mongoosejs.com/docs/api.html

मानगो के स्रोत की जाँच करें। वे एक कनेक्शन खोलते हैं और इसे एक मॉडल ऑब्जेक्ट से बांधते हैं, इसलिए जब मॉडल ऑब्जेक्ट की आवश्यकता होती है, तो एक कनेक्शन DB से किया जाता है। ड्राइवर कनेक्शन पूलिंग का ध्यान रखता है।


देशी mongodb कनेक्टर के लिए मूल nativeis ।
कोडफिनिटी

2

मैंने अपने कोड में कनेक्शन पूलिंग को लागू करने के लिए अपनी परियोजना में कोड के नीचे लागू किया है, इसलिए यह मेरी परियोजना में न्यूनतम कनेक्शन बनाएगा और उपलब्ध कनेक्शन का पुन: उपयोग करेगा

/* Mongo.js*/

var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/yourdatabasename"; 
var assert = require('assert');

var connection=[];
// Create the database connection
establishConnection = function(callback){

                MongoClient.connect(url, { poolSize: 10 },function(err, db) {
                    assert.equal(null, err);

                        connection = db
                        if(typeof callback === 'function' && callback())
                            callback(connection)

                    }

                )



}

function getconnection(){
    return connection
}

module.exports = {

    establishConnection:establishConnection,
    getconnection:getconnection
}

/*app.js*/
// establish one connection with all other routes will use.
var db = require('./routes/mongo')

db.establishConnection();

//you can also call with callback if you wanna create any collection at starting
/*
db.establishConnection(function(conn){
  conn.createCollection("collectionName", function(err, res) {
    if (err) throw err;
    console.log("Collection created!");
  });
};
*/

// anyother route.js

var db = require('./mongo')

router.get('/', function(req, res, next) {
    var connection = db.getconnection()
    res.send("Hello");

});

1

कनेक्शन पूलिंग को लागू करने के लिए सबसे अच्छा तरीका यह है कि आपको एक वैश्विक सरणी चर बनाना चाहिए, जो MongoClient द्वारा लौटाए गए कनेक्शन ऑब्जेक्ट के साथ db नाम रखता है और फिर जब भी आपको डेटाबेस से संपर्क करने की आवश्यकता होती है तो उस कनेक्शन का पुन: उपयोग करें।

  1. आपके Server.js में var global.dbconnections = [] को परिभाषित करता है;

  2. एक कनेक्शन नामकरण ServiceService.js बनाएँ। इसके 2 तरीके होंगे getConnection और createConnection। इसलिए जब उपयोगकर्ता getConnection () को कॉल करेगा, तो यह वैश्विक कनेक्शन चर और रिटर्न कनेक्शन विवरण में विस्तार से मिलेगा यदि पहले से मौजूद है तो इसे createConnection () और रिटर्न कनेक्शन विवरण कहेंगे।

  3. इस सेवा को db_name का उपयोग करके कॉल करें और यह कनेक्शन ऑब्जेक्ट वापस कर देगा यदि इसके पास पहले से ही है तो यह नया कनेक्शन बनाएगा और आपको इसे लौटा देगा।

आशा करता हूँ की ये काम करेगा :)

यहाँ है connectionService.js कोड:

var mongo = require('mongoskin');
var mongodb = require('mongodb');
var Q = require('q');
var service = {};
service.getConnection = getConnection ;
module.exports = service;

function getConnection(appDB){
    var deferred = Q.defer();
    var connectionDetails=global.dbconnections.find(item=>item.appDB==appDB)

    if(connectionDetails){deferred.resolve(connectionDetails.connection);
    }else{createConnection(appDB).then(function(connectionDetails){
            deferred.resolve(connectionDetails);})
    }
    return deferred.promise;
}

function createConnection(appDB){
    var deferred = Q.defer();
    mongodb.MongoClient.connect(connectionServer + appDB, (err,database)=> 
    {
        if(err) deferred.reject(err.name + ': ' + err.message);
        global.dbconnections.push({appDB: appDB,  connection: database});
        deferred.resolve(database);
    })
     return deferred.promise;
} 

0

mongodb.com -> नया प्रोजेक्ट -> नया क्लस्टर -> नया संग्रह -> कनेक्ट -> आईपी पता: 0.0.0.0/0 और डीबी क्रेडिबल -> अपने आवेदन को कनेक्ट करें -> कनेक्शन कनेक्शन स्ट्रिंग और अपने नोड की .env फ़ाइल में पेस्ट करें। एप्लिकेशन और उपयोगकर्ता के लिए वास्तविक पासवर्ड के साथ "" को बदलने के लिए सुनिश्चित करें और "db" नाम के साथ "/ परीक्षण" भी बदलें

नई फ़ाइल बनाएँ .env

CONNECTIONSTRING=x --> const client = new MongoClient(CONNECTIONSTRING) 
PORT=8080 
JWTSECRET=mysuper456secret123phrase

0

यदि एक्सप्रेस का उपयोग करना एक और अधिक सरल तरीका है, जो आपके ऐप के भीतर मार्गों और मॉड्यूल के बीच डेटा साझा करने के लिए एक्सप्रेस में निर्मित सुविधा का उपयोग करना है। App.locals नामक एक ऑब्जेक्ट है। हम इसके गुणों को संलग्न कर सकते हैं और इसे हमारे मार्गों के अंदर से एक्सेस कर सकते हैं। इसका उपयोग करने के लिए, अपने app.js फ़ाइल में अपने mongo कनेक्शन को तुरंत।

var app = express();

MongoClient.connect('mongodb://localhost:27017/')
.then(client =>{
  const db = client.db('your-db');
  const collection = db.collection('your-collection');
  app.locals.collection = collection;
});
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              // view engine setup
app.set('views', path.join(__dirname, 'views'));

यह डेटाबेस कनेक्शन, या वास्तव में कोई अन्य डेटा जिसे आप ऐप के मॉड्यूल के आसपास साझा करना चाहते हैं, अब अतिरिक्त मार्गों को req.app.localsबनाने और आवश्यकता के बिना आपके मार्गों के नीचे तक पहुँचा जा सकता है ।

app.get('/', (req, res) => {
  const collection = req.app.locals.collection;
  collection.find({}).toArray()
  .then(response => res.status(200).json(response))
  .catch(error => console.error(error));
});

यह विधि सुनिश्चित करती है कि आपके पास अपने ऐप की अवधि के लिए डेटाबेस कनेक्शन खुला है जब तक कि आप इसे किसी भी समय बंद नहीं करना चाहते। यह आसानी से सुलभ है req.app.locals.your-collectionऔर किसी भी अतिरिक्त मॉड्यूल के निर्माण की आवश्यकता नहीं है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.