在 NodeJs 中处理 Mongodb 全局连接的最佳方法是什么
What is best way to handle global connection of Mongodb in NodeJs
我使用 Node-Mongo-Native 并尝试设置全局连接变量,但我对两种可能的解决方案感到困惑。大家能帮我看看哪一个好吗?
1.解决方案(这很糟糕,因为每个请求都会尝试创建一个新连接。)
var express = require('express');
var app = express();
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
// Connection URL
var url = '[connectionString]]';
// start server on port 3000
app.listen(3000, '0.0.0.0', function() {
// print a message when the server starts listening
console.log("server starting");
});
// Use connect method to connect to the server when the page is requested
app.get('/', function(request, response) {
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
db.listCollections({}).toArray(function(err, collections) {
assert.equal(null, err);
collections.forEach(function(collection) {
console.log(collection);
});
db.close();
})
response.send('Connected - see console for a list of available collections');
});
});
解决方案(在应用程序初始化时连接并将连接字符串分配给全局变量)。但我认为将连接字符串分配给全局变量不是一个好主意。
变量mongodb;
var url = '[connectionString]';
MongoClient.connect(url, 函数(err, db) {
assert.equal(空,错误);
mongodb=分贝;
}
);
我想在应用程序初始化时创建连接并在整个应用程序生命周期中使用。
你们能帮帮我吗?谢谢
创建一个 Connection
单例模块来管理应用程序数据库连接。
MongoClient 不提供单例连接池,因此您不想在应用中重复调用 MongoClient.connect()
。包装 mongo 客户端的单例 class 适用于我见过的大多数应用程序。
const MongoClient = require('mongodb').MongoClient
class Connection {
static async open() {
if (this.db) return this.db
this.db = await MongoClient.connect(this.url, this.options)
return this.db
}
}
Connection.db = null
Connection.url = 'mongodb://127.0.0.1:27017/test_db'
Connection.options = {
bufferMaxEntries: 0,
reconnectTries: 5000,
useNewUrlParser: true,
useUnifiedTopology: true,
}
module.exports = { Connection }
在您 require('./Connection')
的任何地方,Connection.open()
方法都将可用,Connection.db
属性 如果已初始化,也将可用。
const router = require('express').Router()
const { Connection } = require('../lib/Connection.js')
// This should go in the app/server setup, and waited for.
Connection.open()
router.get('/files', async (req, res) => {
try {
const files = await Connection.db.collection('files').find({})
res.json({ files })
}
catch (error) {
res.status(500).json({ error })
}
})
module.exports = router
模块版本^3.1.8
将连接初始化为承诺:
const MongoClient = require('mongodb').MongoClient
const uri = 'mongodb://...'
const client = new MongoClient(uri)
const connection = client.connect()
然后在您希望对数据库执行操作时调用连接:
app.post('/insert', (req, res) => {
const connect = connection
connect.then(() => {
const doc = { id: 3 }
const db = client.db('database_name')
const coll = db.collection('collection_name')
coll.insertOne(doc, (err, result) => {
if(err) throw err
})
})
})
我就是这样做的。
// custom class
const MongoClient = require('mongodb').MongoClient
const credentials = "mongodb://user:pass@mongo"
class MDBConnect {
static connect (db, collection) {
return MongoClient.connect(credentials)
.then( client => {
return client.db(db).collection(collection);
})
.catch( err => { console.log(err)});
}
static findOne(db, collection, query) {
return MDBConnect.connect(db,collection)
.then(c => {
return c.findOne(query)
.then(result => {
return result;
});
})
}
// create as many as you want
//static find(db, collection, query)
//static insert(db, collection, query)
// etc etc etc
}
module.exports = MDBConnect;
// in the route file
var express = require('express');
var router = express.Router();
var ObjectId = require('mongodb').ObjectId;
var MDBConnect = require('../storage/MDBConnect');
// Usages
router.get('/q/:id', function(req, res, next) {
let sceneId = req.params.id;
// user case 1
MDBConnect.connect('gameapp','scene')
.then(c => {
c.findOne({_id: ObjectId(sceneId)})
.then(result => {
console.log("result: ",result);
res.json(result);
})
});
// user case 2, with query
MDBConnect.findOne('gameapp','scene',{_id: ObjectId(sceneId)})
.then(result => {
res.json(result);
});
});
另一种更直接的方法是利用 Express 的内置功能在应用程序中的路由和模块之间共享数据。有一个名为 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
轻松访问,并且不需要创建任何其他模块。
在 Express 中,您可以像这样添加 mongo 连接
import {MongoClient} from 'mongodb';
import express from 'express';
import bodyParser from 'body-parser';
let mongoClient = null;
MongoClient.connect(config.mongoURL, {useNewUrlParser: true, useUnifiedTopology: true},function (err, client) {
if(err) {
console.log('Mongo connection error');
} else {
console.log('Connected to mongo DB');
mongoClient = client;
}
})
let app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use((req,res,next)=>{
req.db = mongoClient.db('customer_support');
next();
});
以后您可以 req.db
访问它
router.post('/hello',async (req,res,next)=>{
let uname = req.body.username;
let userDetails = await getUserDetails(req.db,uname)
res.statusCode = 200;
res.data = userDetails;
next();
});
我对答案做了很多研究,但找不到能说服我的解决方案,所以我开发了自己的解决方案。
const {MongoClient} = require("mongodb");
class DB {
static database;
static client;
static async setUp(url) {
if(!this.client) {
await this.setClient(url);
await this.setConnection();
}
return this.database;
}
static async setConnection() {
this.database = this.client.db("default");
}
static async setClient(url) {
console.log("Connecting to database");
const client = new MongoClient(url);
await client.connect();
this.client = client;
}
}
module.exports = DB;
用法:
const DB = require("./Path/to/DB");
(async () => {
const database = await DB.setUp();
const users = await database.collection("users").findOne({ email: "" });
});
这是 的一个版本,它允许您在使用连接时定义 database
和 collection
。不确定它是否与他的解决方案一样 'water tight',但评论太长了。
我删除了 Connection.options
,因为他们给我错误 ()。
lib/Connection.js
const MongoClient = require('mongodb').MongoClient;
const { connection_string } = require('./environment_variables');
class Connection {
static async open() {
if (this.conn) return this.conn;
this.conn = await MongoClient.connect(connection_string);
return this.conn;
}
}
Connection.conn = null;
Connection.url = connection_string;
module.exports = { Connection };
testRoute.js
const express = require('express');
const router = express.Router();
const { Connection } = require('../lib/Connection.js');
Connection.open();
router.route('/').get(async (req, res) => {
try {
const query = { username: 'my name' };
const collection = Connection.conn.db('users').collection('users');
const result = await collection.findOne(query);
res.json({ result: result });
} catch (error) {
console.log(error);
res.status(500).json({ error });
}
});
module.exports = router;
如果您想从路由文件中取出中间件:
testRoute.js 变为:
const express = require('express');
const router = express.Router();
const test_middleware_01 = require('../middleware/test_middleware_01');
router.route('/').get(test_middleware_01);
module.exports = router;
中间件定义在middleware/test_middleware_01.js:
const { Connection } = require('../lib/Connection.js');
Connection.open();
const test_middleware_01 = async (req, res) => {
try {
const query = { username: 'my name' };
const collection = Connection.conn.db('users').collection('users');
const result = await collection.findOne(query);
res.json({ result: result });
} catch (error) {
console.log(error);
res.status(500).json({ error });
}
};
module.exports = test_middleware_01;
我使用 Node-Mongo-Native 并尝试设置全局连接变量,但我对两种可能的解决方案感到困惑。大家能帮我看看哪一个好吗? 1.解决方案(这很糟糕,因为每个请求都会尝试创建一个新连接。)
var express = require('express');
var app = express();
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
// Connection URL
var url = '[connectionString]]';
// start server on port 3000
app.listen(3000, '0.0.0.0', function() {
// print a message when the server starts listening
console.log("server starting");
});
// Use connect method to connect to the server when the page is requested
app.get('/', function(request, response) {
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
db.listCollections({}).toArray(function(err, collections) {
assert.equal(null, err);
collections.forEach(function(collection) {
console.log(collection);
});
db.close();
})
response.send('Connected - see console for a list of available collections');
});
});
解决方案(在应用程序初始化时连接并将连接字符串分配给全局变量)。但我认为将连接字符串分配给全局变量不是一个好主意。
变量mongodb; var url = '[connectionString]'; MongoClient.connect(url, 函数(err, db) {
assert.equal(空,错误); mongodb=分贝; } );
我想在应用程序初始化时创建连接并在整个应用程序生命周期中使用。
你们能帮帮我吗?谢谢
创建一个 Connection
单例模块来管理应用程序数据库连接。
MongoClient 不提供单例连接池,因此您不想在应用中重复调用 MongoClient.connect()
。包装 mongo 客户端的单例 class 适用于我见过的大多数应用程序。
const MongoClient = require('mongodb').MongoClient
class Connection {
static async open() {
if (this.db) return this.db
this.db = await MongoClient.connect(this.url, this.options)
return this.db
}
}
Connection.db = null
Connection.url = 'mongodb://127.0.0.1:27017/test_db'
Connection.options = {
bufferMaxEntries: 0,
reconnectTries: 5000,
useNewUrlParser: true,
useUnifiedTopology: true,
}
module.exports = { Connection }
在您 require('./Connection')
的任何地方,Connection.open()
方法都将可用,Connection.db
属性 如果已初始化,也将可用。
const router = require('express').Router()
const { Connection } = require('../lib/Connection.js')
// This should go in the app/server setup, and waited for.
Connection.open()
router.get('/files', async (req, res) => {
try {
const files = await Connection.db.collection('files').find({})
res.json({ files })
}
catch (error) {
res.status(500).json({ error })
}
})
module.exports = router
模块版本^3.1.8
将连接初始化为承诺:
const MongoClient = require('mongodb').MongoClient
const uri = 'mongodb://...'
const client = new MongoClient(uri)
const connection = client.connect()
然后在您希望对数据库执行操作时调用连接:
app.post('/insert', (req, res) => {
const connect = connection
connect.then(() => {
const doc = { id: 3 }
const db = client.db('database_name')
const coll = db.collection('collection_name')
coll.insertOne(doc, (err, result) => {
if(err) throw err
})
})
})
我就是这样做的。
// custom class
const MongoClient = require('mongodb').MongoClient
const credentials = "mongodb://user:pass@mongo"
class MDBConnect {
static connect (db, collection) {
return MongoClient.connect(credentials)
.then( client => {
return client.db(db).collection(collection);
})
.catch( err => { console.log(err)});
}
static findOne(db, collection, query) {
return MDBConnect.connect(db,collection)
.then(c => {
return c.findOne(query)
.then(result => {
return result;
});
})
}
// create as many as you want
//static find(db, collection, query)
//static insert(db, collection, query)
// etc etc etc
}
module.exports = MDBConnect;
// in the route file
var express = require('express');
var router = express.Router();
var ObjectId = require('mongodb').ObjectId;
var MDBConnect = require('../storage/MDBConnect');
// Usages
router.get('/q/:id', function(req, res, next) {
let sceneId = req.params.id;
// user case 1
MDBConnect.connect('gameapp','scene')
.then(c => {
c.findOne({_id: ObjectId(sceneId)})
.then(result => {
console.log("result: ",result);
res.json(result);
})
});
// user case 2, with query
MDBConnect.findOne('gameapp','scene',{_id: ObjectId(sceneId)})
.then(result => {
res.json(result);
});
});
另一种更直接的方法是利用 Express 的内置功能在应用程序中的路由和模块之间共享数据。有一个名为 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
轻松访问,并且不需要创建任何其他模块。
在 Express 中,您可以像这样添加 mongo 连接
import {MongoClient} from 'mongodb';
import express from 'express';
import bodyParser from 'body-parser';
let mongoClient = null;
MongoClient.connect(config.mongoURL, {useNewUrlParser: true, useUnifiedTopology: true},function (err, client) {
if(err) {
console.log('Mongo connection error');
} else {
console.log('Connected to mongo DB');
mongoClient = client;
}
})
let app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use((req,res,next)=>{
req.db = mongoClient.db('customer_support');
next();
});
以后您可以 req.db
访问它router.post('/hello',async (req,res,next)=>{
let uname = req.body.username;
let userDetails = await getUserDetails(req.db,uname)
res.statusCode = 200;
res.data = userDetails;
next();
});
我对答案做了很多研究,但找不到能说服我的解决方案,所以我开发了自己的解决方案。
const {MongoClient} = require("mongodb");
class DB {
static database;
static client;
static async setUp(url) {
if(!this.client) {
await this.setClient(url);
await this.setConnection();
}
return this.database;
}
static async setConnection() {
this.database = this.client.db("default");
}
static async setClient(url) {
console.log("Connecting to database");
const client = new MongoClient(url);
await client.connect();
this.client = client;
}
}
module.exports = DB;
用法:
const DB = require("./Path/to/DB");
(async () => {
const database = await DB.setUp();
const users = await database.collection("users").findOne({ email: "" });
});
这是 database
和 collection
。不确定它是否与他的解决方案一样 'water tight',但评论太长了。
我删除了 Connection.options
,因为他们给我错误 (
lib/Connection.js
const MongoClient = require('mongodb').MongoClient;
const { connection_string } = require('./environment_variables');
class Connection {
static async open() {
if (this.conn) return this.conn;
this.conn = await MongoClient.connect(connection_string);
return this.conn;
}
}
Connection.conn = null;
Connection.url = connection_string;
module.exports = { Connection };
testRoute.js
const express = require('express');
const router = express.Router();
const { Connection } = require('../lib/Connection.js');
Connection.open();
router.route('/').get(async (req, res) => {
try {
const query = { username: 'my name' };
const collection = Connection.conn.db('users').collection('users');
const result = await collection.findOne(query);
res.json({ result: result });
} catch (error) {
console.log(error);
res.status(500).json({ error });
}
});
module.exports = router;
如果您想从路由文件中取出中间件:
testRoute.js 变为:
const express = require('express');
const router = express.Router();
const test_middleware_01 = require('../middleware/test_middleware_01');
router.route('/').get(test_middleware_01);
module.exports = router;
中间件定义在middleware/test_middleware_01.js:
const { Connection } = require('../lib/Connection.js');
Connection.open();
const test_middleware_01 = async (req, res) => {
try {
const query = { username: 'my name' };
const collection = Connection.conn.db('users').collection('users');
const result = await collection.findOne(query);
res.json({ result: result });
} catch (error) {
console.log(error);
res.status(500).json({ error });
}
};
module.exports = test_middleware_01;