Как мне управлять подключениями MongoDB в веб-приложении Node.js?

Я используюУзел-MongoDB-родной драйвер с MongoDB, чтобы написать сайт.

У меня есть несколько вопросов о том, как управлять соединениями:

Is it enough using only one MongoDB connection for all requests? Are there any performance issues? If not, can I setup a global connection to use in the whole application?

If not, is it good if I open a new connection when request arrives, and close it when handled the request? Is it expensive to open and close a connection?

Should I use a global connection pool? I hear the driver has a native connection pool. Is it a good choice?

If I use a connection pool, how many connections should be used?

Are there other things I should notice?

 Ionică Bizău30 июн. 2014 г., 14:55
Почему вы не принимаетеthis answer?
 Freewind30 июн. 2014 г., 17:49
@ Ionic; Biz & # xE3; у вас, извините, я не использую nodejs в течение долгого времени, которого я не видел. Спасибо за ваш комментарий ~

Ответы на вопрос(10)

Откройте новое соединение при запуске приложения 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;
Source: How to Open Database Connections in a Node.js/Express App
 24 сент. 2018 г., 23:37
Никогда раньше не слышал о app.locals, но я рад, что вы познакомили меня с ними здесь
 15 дек. 2015 г., 16:01
Это создает одно соединение с базой данных ... если вы хотите использовать пулы, вы должны создавать / закрывать при каждом использовании
 12 июн. 2016 г., 06:04
Не по теме, это самый странный файл NodeJS, который я когда-либо видел.
 01 мар. 2019 г., 18:00
Мне очень помогли! Я делаю ошибку, чтобы создать / закрыть соединение с БД для каждого запроса, производительность моего приложения упала с этим.

Вот код, который будет управлять вашими подключениями 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 документация, Посмотрите на это.

 11 июл. 2018 г., 03:40
Обновление с 5.x: var option = {numberOfRetries: 5, auto_reconnect: true, poolSize: 40, connectTimeoutMS: 30000};

Управляйте пулами соединений Монго в одном автономном модуле. Этот подход обеспечивает два преимущества. Во-первых, это делает ваш код модульным и его легче тестировать. Во-вторых, вам не нужно смешивать соединение с базой данных в объекте запроса, который НЕ является местом для объекта соединения с базой данных. (Учитывая природу JavaScript, я считаю очень опасным смешивать что-либо с объектом, созданным библиотечным кодом). Так что с этим вам нужно только рассмотреть модуль, который экспортирует два метода.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;
}
 22 авг. 2017 г., 16:08
@ Stewart Как бы вы справились со случаем, когда монго-соединение умирает на более поздней стадии после соединения? В этом сценарии все вызовы get () не будут выполнены, пока приложение узла не будет перезапущено
 02 июн. 2017 г., 13:52
Более того, вы можете просто избавиться от функции connect () и проверить функцию get (), чтобы увидеть, является ли соединение пустым, и вызвать connect для вас, если оно есть. У get () всегда возвращаются обещания. Так я управляю своим соединением, и оно прекрасно работает. Это использование шаблона синглтона.
 06 июн. 2017 г., 02:31
@Stewart Способ, которым я структурирую приложения / сервисы, обычно заключается в получении конфигурации из базы данных при запуске. Таким образом, приложение не запустится, если база данных недоступна. Кроме того, поскольку первый запрос всегда выполняется при запуске, нет проблем с показателями с таким дизайном. Также повторно сгенерируйте исключение соединения с одним местом в синглтоне с явной ошибкой, которую он не может соединить. Так как приложению все равно нужно перехватывать ошибки базы данных при использовании соединения, это не приводит к какой-либо дополнительной встроенной обработке.
 05 июн. 2017 г., 05:23
@ java-addict301 Хотя этот подход обеспечивает более упорядоченный API, у него есть два недостатка. Во-первых, нет определенного способа проверить наличие ошибок подключения. Вы должны были бы обрабатывать эту строку везде, где бы вы ни звонили. Мне нравится рано выходить из строя с соединениями с базой данных и обычно я не позволяю приложению загружаться без соединения с базой данных. Другая проблема - пропускная способность. Поскольку у вас нет активного соединения, вам, возможно, придется подождать немного дольше при первом вызове get (), который вы не сможете контролировать. Может исказить ваши показатели отчетности.
 09 мая 2017 г., 10:27
очень полезно, именно то, что я искал!

Вы должны создать соединение как сервис, а затем использовать его при необходимости.

// 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
 15 нояб. 2017 г., 08:09
Если mongo не может подключиться, MongoClient.close () выдает ошибку. Но хорошее решение для оригинальной проблемы.

Если у вас есть Express.js, вы можете использоватьэкспресс-Монго-DB для кэширования и совместного использования соединения MongoDB между запросами без пула (поскольку в принятом ответе говорится, что это правильный способ поделиться соединением).

Если нет - вы можете посмотреть на его исходный код и использовать его в другом фреймворке.

Я использовал generic-pool с подключениями redis в своем приложении - я очень рекомендую его. Он универсален, и я точно знаю, что он работает с mysql, поэтому я не думаю, что у вас возникнут какие-либо проблемы с ним и Монго.

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

 11 авг. 2014 г., 22:49
Mongo уже выполняет пул соединений в драйвере, однако я сопоставил мои монго-соединения с интерфейсом, который соответствует пулу узлов, таким образом, все мои соединения следуют одному и тому же шаблону, даже если в случае с монго очистка не выполняется. на самом деле вызвать что-нибудь.
Решение Вопроса

Основной коммиттер для node-mongodb-native говорит:

You open do MongoClient.connect once when your app boots up and reuse the db object. It's not a singleton connection pool each .connect creates a new connection pool.

Итак, чтобы ответить на ваш вопрос напрямую, повторно используйте объект db, полученный из MongoClient.connect (). Это обеспечивает объединение в пул и обеспечивает заметное увеличение скорости по сравнению с открытием / закрытием соединений при каждом действии БД.

 22 апр. 2013 г., 15:16
Должен быть помечен как правильный ответ.
 30 сент. 2013 г., 03:12
Это правильный ответ. Боже мой, представьте, что мне приходится открывать и закрывать каждый раз, когда я что-то делаю, это будет 350K в час только для моих вкладышей! Это похоже на атаку на мой собственный сервер.
 13 авг. 2013 г., 16:56
Это правильный ответ. Принятый ответ очень неправильный, так как он говорит, что нужно открывать пул соединений для каждого запроса, а затем закрывать его после этого. Ужасная архитектура.
 24 июл. 2013 г., 19:19
Ссылка на MongoClient.connect ()mongodb.github.io/node-mongodb-native/driver-articles/…
 08 авг. 2014 г., 20:15
@Cracker: Если у вас есть экспресс-приложение, вы можете сохранить объект БД вreq.db с этим промежуточным ПО:github.com/floatdrop/express-mongo-db

Наилучший подход для реализации пула соединений заключается в том, что вы должны создать одну глобальную переменную массива, содержащую имя базы данных с объектом соединения, возвращенным MongoClient, а затем повторно использовать это соединение всякий раз, когда вам нужно связаться с базой данных.

In your Server.js define var global.dbconnections = [];

Create a Service naming connectionService.js. It will have 2 methods getConnection and createConnection. So when user will call getConnection(), it will find detail in global connection variable and return connection details if already exists else it will call createConnection() and return connection Details.

Call this service using db_name and it will return connection object if it already have else it will create new connection and return it to you.

Надеюсь, поможет :)

Вот код 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;
} 

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

Проверьте источник мангуста. Они открывают соединение и связывают его с объектом Model, поэтому, когда требуется объект Model, устанавливается соединение с БД. Драйвер заботится о пуле соединений.

Я реализовал приведенный ниже код в своем проекте, чтобы реализовать пул соединений в моем коде, чтобы он создал минимальное соединение в моем проекте и повторно использовал доступное соединение

/* 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");

});

Ваш ответ на вопрос