如何在Node.js Web应用程序中pipe理MongoDB连接?
我正在使用MongoDB的node-mongodb-native驱动写一个网站。
我有一些关于如何pipe理连接的问题:
-
对于所有请求只使用一个MongoDB连接是否足够? 有没有任何性能问题? 如果没有,我可以设置一个全局连接在整个应用程序中使用吗?
-
如果不是,请求到达时打开一个新的连接,并且在处理请求时closures它是否好? 打开和closures连接是否昂贵?
-
我应该使用全局连接池吗? 我听说驱动程序有一个本机连接池。 这是不错的select吗?
-
如果我使用连接池,应该使用多less个连接?
-
还有其他的事情我应该注意到吗?
node-mongodb-native的主要提交者说 :
当您的应用启动并重新使用db对象时,您将打开一次MongoClient.connect。 这不是一个单独连接池每个.connect创build一个新的连接池。
所以,要直接回答你的问题,重用从MongoClient.connect()得到的db对象。 这给你池,并将提供一个明显的速度增加相比,打开/closures每个数据库操作的连接。
当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应用程序中打开数据库连接
这是一些将pipe理你的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文档 。 看看它。
如果你有Express.js,你可以使用express-mongo-db来caching和共享不带池的请求之间的MongoDB连接(因为接受的答案是共享连接的正确方式)。
如果没有 – 你可以看看它的源代码,并在另一个框架中使用它。
我一直在我的应用程序使用通用池与redis连接 – 我强烈推荐它。 它的generics,我肯定知道它适用于MySQL,所以我不认为你会有任何问题,它和Mongo
在一个独立的模块中pipe理mongo连接池。 这种方法提供了两个好处。 首先它保持你的代码模块化,更容易testing。 其次,你不是强迫你的请求对象中的数据库连接,而不是数据库连接对象的地方。 (鉴于JavaScript的本质,我认为将任何东西混合到由库代码构build的对象中是非常危险的)。 所以,你只需要考虑一个导出两个方法的模块。 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
如果使用与以下相同的方式设置db模块,则不仅可以确保应用程序在除非有数据库连接的情况下才能启动,还可以使用访问数据库连接池的全局方法如果你没有连接。
// 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; }
http://mongoosejs.com/docs/api.html
检查mongoose的来源。 他们打开一个连接,并将其绑定到一个Model对象,所以当需要模型Object时,连接到DB。 驱动程序负责连接池。
您应该创build一个连接作为服务,然后在需要时重用。
// 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
我在我的项目中实现了下面的代码来实现我的代码中的连接池,所以它会在我的项目中创build一个最小的连接,并重用可用的连接
/* 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"); });