我使用node-mongodb-native驱动与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?


当前回答

如果有人想在2021年用Typescript工作,这是我正在使用的:

import { MongoClient, Collection } from "mongodb";

const FILE_DB_HOST = process.env.FILE_DB_HOST as string;
const FILE_DB_DATABASE = process.env.FILE_DB_DATABASE as string;
const FILES_COLLECTION = process.env.FILES_COLLECTION as string;

if (!FILE_DB_HOST || !FILE_DB_DATABASE || !FILES_COLLECTION) {
  throw "Missing FILE_DB_HOST, FILE_DB_DATABASE, or FILES_COLLECTION environment variables.";
}

const client = new MongoClient(FILE_DB_HOST, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

class Mongoose {
  static FilesCollection: Collection;

  static async init() {
    const connection = await client.connect();
    const FileDB = connection.db(FILE_DB_DATABASE);
    Mongoose.FilesCollection = FileDB.collection(FILES_COLLECTION);
  }
}


Mongoose.init();

export default Mongoose;

我相信如果请求发生得太快(在蒙古.init()有时间完成之前),将会抛出一个错误,因为Mongoose。FilesCollection将未定义。

import { Request, Response, NextFunction } from "express";
import Mongoose from "../../mongoose";

export default async function GetFile(req: Request, res: Response, next: NextFunction) {
  const files = Mongoose.FilesCollection;
  const file = await files.findOne({ fileName: "hello" });
  res.send(file);
}

例如,如果您调用文件。findOne({…})和猫鼬。FilesCollection未定义,那么您将得到一个错误。

其他回答

如果你有Express.js,你可以使用express- MongoDB -db在请求之间缓存和共享MongoDB连接,而不需要一个池(因为接受的答案说这是共享连接的正确方式)。

如果没有,你可以查看它的源代码并在另一个框架中使用它。

您应该将连接创建为服务,然后在需要时重用它。

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

当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/Express App中打开数据库连接

node-mongodb-native的主提交者说:

打开MongoClient。连接一次,当你的应用程序启动和重用 db对象。每个.connect并不是一个单独的连接池 创建一个新的连接池。

因此,为了直接回答您的问题,重用MongoClient.connect()生成的db对象。这为您提供了池化,与在每个db操作上打开/关闭连接相比,将提供显著的速度提高。

下面是一些管理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文档的。看一看。