如何通过 Nodej 应用程序和模块正确重用到 Mongodb 的连接

我一直在阅读和阅读,但仍然困惑什么是在整个 NodeJs 应用程序中共享相同数据库(MongoDb)连接的最佳方式。据我所知,连接应该打开时,应用程序启动和重用之间的模块。我目前对最佳方式的想法是 server.js(所有内容开始的主文件)连接到数据库并创建传递给模块的对象变量。一旦连接,这个变量将被模块代码根据需要使用,并且这个连接保持打开状态。例如:

    var MongoClient = require('mongodb').MongoClient;
var mongo = {}; // this is passed to modules and code


MongoClient.connect("mongodb://localhost:27017/marankings", function(err, db) {
if (!err) {
console.log("We are connected");


// these tables will be passed to modules as part of mongo object
mongo.dbUsers = db.collection("users");
mongo.dbDisciplines = db.collection("disciplines");


console.log("aaa " + users.getAll()); // displays object and this can be used from inside modules


} else
console.log(err);
});


var users = new(require("./models/user"))(app, mongo);
console.log("bbb " + users.getAll()); // not connected at the very first time so displays undefined

然后另一个模块 models/user看起来像这样:

Users = function(app, mongo) {


Users.prototype.addUser = function() {
console.log("add user");
}


Users.prototype.getAll = function() {


return "all users " + mongo.dbUsers;


}
}


module.exports = Users;

现在我有可怕的感觉,这是错误的,所以有任何明显的问题与这种方法,如果是这样,如何使它更好?

99022 次浏览

您可以创建一个 mongoUtil.js模块,该模块具有连接到 mongo 并返回 mongo db 实例的函数:

const MongoClient = require( 'mongodb' ).MongoClient;
const url = "mongodb://localhost:27017";


var _db;


module.exports = {


connectToServer: function( callback ) {
MongoClient.connect( url,  { useNewUrlParser: true }, function( err, client ) {
_db  = client.db('test_db');
return callback( err );
} );
},


getDb: function() {
return _db;
}
};

要使用它,你需要在你的 app.js中这样做:

var mongoUtil = require( 'mongoUtil' );


mongoUtil.connectToServer( function( err, client ) {
if (err) console.log(err);
// start the rest of your app here
} );

然后,当您需要访问其他地方的 mongo 时,比如在另一个 .js文件中,您可以这样做:

var mongoUtil = require( 'mongoUtil' );
var db = mongoUtil.getDb();


db.collection( 'users' ).find();

这样做的原因是,在节点中,当模块被 require化时,它们只被加载/源代码一次,所以最终只有一个 _db实例,而 mongoUtil.getDb()总是返回同一个实例。

注意,代码未经测试。

Go-oleg 基本上是正确的,但是在这些日子里,你(可能)不想使用“ monGodb”本身,而是使用一些框架,它们会为你做很多“脏活”。

例如,猫鼬是最常见的一种,这是我们在 server.js初始文件中看到的:

const mongoose = require('mongoose');
const options = {server: {socketOptions: {keepAlive: 1}}};
mongoose.connect(config.db, options);

这就是设置它所需要的一切。现在在代码中的任何地方使用它

const mongoose = require('mongoose');

然后得到用 mongoose.connect设置的实例

如果使用 Express,则可以使用 Mongo-Express-req模块,该模块允许您在请求对象中获取数据库连接。

安装

npm install --save mongo-express-req

Server.js

var app = require('express')();


var mongoExpressReq = require('mongo-express-req');
app.use(mongoExpressReq('mongodb://localhost/test'));

路由/用户

app.get('/', function (req, res, next) {
req.db // => Db object
});

注意: mongo-express-req叉子,不维持 express-mongo-db

下面是我如何使用现代语法,基于 go-oleg 的例子。

我在代码中加了一些注释。

./db/monGodb.js

 const MongoClient = require('mongodb').MongoClient
const uri = 'mongodb://user:password@localhost:27017/dbName'
let _db


const connectDB = async (callback) => {
try {
MongoClient.connect(uri, (err, db) => {
_db = db
return callback(err)
})
} catch (e) {
throw e
}
}


const getDB = () => _db


const disconnectDB = () => _db.close()


module.exports = { connectDB, getDB, disconnectDB }

./index.js

 // Load MongoDB utils
const MongoDB = require('./db/mongodb')
// Load queries & mutations
const Users = require('./users')


// Improve debugging
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at:', p, 'reason:', reason)
})


const seedUser = {
name: 'Bob Alice',
email: 'test@dev.null',
bonusSetting: true
}


// Connect to MongoDB and put server instantiation code inside
// because we start the connection first
MongoDB.connectDB(async (err) => {
if (err) throw err
// Load db & collections
const db = MongoDB.getDB()
const users = db.collection('users')


try {
// Run some sample operations
// and pass users collection into models
const newUser = await Users.createUser(users, seedUser)
const listUsers = await Users.getUsers(users)
const findUser = await Users.findUserById(users, newUser._id)


console.log('CREATE USER')
console.log(newUser)
console.log('GET ALL USERS')
console.log(listUsers)
console.log('FIND USER')
console.log(findUser)
} catch (e) {
throw e
}


const desired = true
if (desired) {
// Use disconnectDB for clean driver disconnect
MongoDB.disconnectDB()
process.exit(0)
}
// Server code anywhere above here inside connectDB()
})

./users/index.js

 const ObjectID = require('mongodb').ObjectID


// Notice how the users collection is passed into the models
const createUser = async (users, user) => {
try {
const results = await users.insertOne(user)
return results.ops[0]
} catch (e) {
throw e
}
}


const getUsers = async (users) => {
try {
const results = await users.find().toArray()
return results
} catch (e) {
throw e
}
}


const findUserById = async (users, id) => {
try {
if (!ObjectID.isValid(id)) throw 'Invalid MongoDB ID.'
const results = await users.findOne(ObjectID(id))
return results
} catch (e) {
throw e
}
}


// Export garbage as methods on the Users object
module.exports = { createUser, getUsers, findUserById }

一个基于公认答案的经过测试的解决方案:

Mongodbutil.js:

var MongoClient = require( 'mongodb' ).MongoClient;
var _db;
module.exports = {
connectToServer: function( callback ) {
MongoClient.connect( "<connection string>", function( err, client ) {
_db = client.db("<database name>");
return callback( err );
} );
},
getDb: function() {
return _db;
}
};

App.js:

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));


var mongodbutil = require( './mongodbutil' );
mongodbutil.connectToServer( function( err ) {
//app goes online once this callback occurs
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var companiesRouter = require('./routes/companies');
var activitiesRouter = require('./routes/activities');
var registerRouter = require('./routes/register');
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/companies', companiesRouter);
app.use('/activities', activitiesRouter);
app.use('/register', registerRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
//end of calback
});


module.exports = app;

返回文章页面活动——一条路线译者:

var express = require('express');
var router = express.Router();
var mongodbutil = require( '../mongodbutil' );
var db = mongodbutil.getDb();


router.get('/', (req, res, next) => {
db.collection('activities').find().toArray((err, results) => {
if (err) return console.log(err)
res.render('activities', {activities: results, title: "Activities"})
});
});


router.post('/', (req, res) => {
db.collection('activities').save(req.body, (err, result) => {
if (err) return console.log(err)
res.redirect('/activities')
})
});


module.exports = router;

将连接初始化为承诺:

const MongoClient = require('mongodb').MongoClient
const uri = 'mongodb://...'
const client = new MongoClient(uri)
const connection = client.connect() // initialized connection

然后,只要您希望在数据库上执行操作,就可以调用该连接:

    // if I want to insert into the database...
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
})
})

我们可以创建一个 dbconnect 文件,比如 dbconnection.js

const MongoClient = require('mongodb').MongoClient
const mongo_url = process.env.MONGO_URL;


module.exports = {
connect: async function(callback) {
var connection;
await new Promise((resolve, reject) => {
MongoClient.connect(mongo_url, {
useNewUrlParser: true
}, (err, database) => {
if (err)
reject();
else {
connection = database;
resolve();
}
});
});
return connection;
}


};

然后在你的应用程序中使用这个文件

var connection = require('../dbconnection');

然后像这样在你的异步函数中使用

db  = await connection.connect();

希望能成功

可以通过许多方式对其进行调整,以便在某些地方接受配置对象,但总体而言,它类似于代码的布局方式,尽管使用了更现代的 JS 语法。可以很容易地重写到原型和回调,如果这是你的要求。

Mongo.js

const { MongoClient } = require('mongodb');
const config = require('./config');
const Users = require('./Users');
const conf = config.get('mongodb');


class MongoBot {
constructor() {
const url = `mongodb://${conf.hosts.join(',')}`;


this.client = new MongoClient(url, conf.opts);
}
async init() {
await this.client.connect();
console.log('connected');


this.db = this.client.db(conf.db);
this.Users = new Users(this.db);
}
}


module.exports = new MongoBot();

Users.js

class User {
constructor(db) {
this.collection = db.collection('users');
}
async addUser(user) {
const newUser = await this.collection.insertOne(user);
return newUser;
}
}
module.exports = User;

应用程序

const mongo = require('./mongo');


async function start() {
// other app startup stuff...
await mongo.init();
// other app startup stuff...
}
start();

翻译

const { Users } = require('./mongo');


async function someFunction(userInfo) {
const user = await Users.addUser(userInfo);
return user;
}

如果您选择在应用程序中使用 monose,请用以下代码片段编辑 app.js 文件

应用程序

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/Your_Data_Base_Name', {useNewUrlParser:true})
.then((res) => {
console.log(' ########### Connected to mongDB ###########');
})
.catch((err) => {
console.log('Error in connecting to mongoDb' + err);
});`

下一步: 为应用程序定义需要的模型,并直接执行 CRUD 操作,例如

BlogSchema.js

 const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const blogSchema = new Schema({
_id : mongoose.Schema.Types.ObjectId,
title : {
type : 'String',
unique : true,
required : true
},
description : String,
comments : [{type : mongoose.Schema.Types.ObjectId, ref: 'Comment'}]
});
module.exports = mongoose.model('Blog', blogSchema);

用法 CreateBlog.js

const Blog = require('../models/blogSchema');
exports.createBlog = (req, res, next) => {
const blog = new Blog({
_id : new mongoose.Types.ObjectId,
title : req.body.title,
description : req.body.description,
});
blog.save((err, blog) => {
if(err){
console.log('Server Error save fun failed');
res.status(500).json({
msg : "Error occured on server side",
err : err
})
}else{
//do something....
}

你不需要总是连接到 mogoDB... 。

var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017/';
var Pro1;


module.exports = {
DBConnection:async function()
{
Pro1 = new Promise(async function(resolve,reject){
MongoClient.connect(url, { useNewUrlParser: true },function(err, db) {
if (err) throw err;
resolve(db);
});
});
},
getDB:async function(Blockchain , Context)
{
bc = Blockchain;
contx = Context;
Pro1.then(function(_db)
{
var dbo = _db.db('dbname');
dbo.collection('collectionname').find().limit(1).skip(0).toArray(function(err,result) {
if (err) throw err;
console.log(result);
});
});
},
closeDB:async function()
{
Pro1.then(function(_db){
_db.close();
});
}
};

我有点晚了,但我会加上我的解决方案。与这里的答案相比,这是一个非常愚蠢的方法。

无论如何,如果您正在使用 MongoDB 版本4.0和 Node.js 3.0(或更高版本) ,您可以使用来自 MongoClientisConnected()函数。

const MongoClient = require('mongodb').MongoClient;
const uri = "<your connection url>";
const client = new MongoClient(uri, { useNewUrlParser: true });


if (client.isConnected()) {
execute();
} else {
client.connect().then(function () {
execute();
});
}


function execute() {
// Do anything here
// Ex: client.db("mydb").collection("mycol");
}

这招对我很管用,希望能有帮助。

以下是我在2020年的设置:

./utils/database. js

const { MongoClient } = require('mongodb');


class Mongo {
constructor () {
this.client = new MongoClient("mongodb://127.0.0.1:27017/my-app", {
useNewUrlParser: true,
useUnifiedTopology: true
});
}


async main () {
await this.client.connect();
console.log('Connected to MongoDB');


this.db = this.client.db();
}
}


module.exports = new Mongo();

/app.js

const mongo = require('./utils/database');
const express = require('express');


const app = express();


const boot = async () => {
await mongo.main();
app.listen(3000);
};


boot();

我发现这个方法很有效:)

蒙古语

import { MongoClient } from 'mongodb';
const uri =
'MONGOSTRING';


let connPoolPromise: any = null;


const mongoPoolPromise = () => {
if (connPoolPromise) return connPoolPromise;


connPoolPromise = new Promise((resolve, reject) => {
const conn = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});


if (conn.isConnected()) {
return resolve(conn);
} else {
conn
.connect()
.then(() => {
return resolve(conn.db('DATABASENAME'));
})
.catch(err => {
console.log(err);
reject(err);
});
}
});


return connPoolPromise;
};


export = {
mongoPoolPromise,
};

AnyFile.ts

const { mongoPoolPromise } = require('./mongoUtil');


async function getProducts() {
const db = await mongoPoolPromise();
const data = await db
.collection('myCollection')
.find({})
.toArray();
console.log(data);
return data;
}


export { getProducts };
const express = require('express')
const server = express()
const mongoClient = require('./MongoDB.js').client
const port = 3000
;(async () => {
await mongoClient.connect()
server.listen(port, () => console.log(`Server is listening on port ${port}!`))
})().catch(console.error)

我迟到了,但希望这个答案能帮到某人,这是一个函数代码:

Db.js

const MongoClient = require("mongodb").MongoClient
const urlMongo = "mongodb://localhost:27017"


var db;


function connectToServer( callback ) {
MongoClient.connect(urlMongo,  { useUnifiedTopology: true , useNewUrlParser: true }, function( err, client ) {
db  = client.db('auth');
return callback( err );
})
}


function getDb() {
return db
}


module.exports = {connectToServer, getDb}

我们导出一个函数来连接 mongo,另一个函数来获取连接的 de instanceof。

应用程序

const express = require('express')
const app = express()


const mongo = require('./db.js');


mongo.connectToServer( function( err) {
if (err) console.log(err);
const auth = require('./modulos')


app.post('/login', (req, res) => { auth.login(req, res)})
app.listen(3000, function () { console.log('Corriendo en puerto 3000')})


});

在初始化连接之后,我们必须执行 auth 模块的要求,否则 getDb 函数将返回未定义的内容。

Module.js

const db = require('../db.js').getDb()
const usuariosCollection = db.collection('usuarios')


function login(req, res){
usuariosCollection.find({ 'username': 'Fran' }).toArray(function (err, doc) {
...
})
}

由于这是用 Express 标记的,我想我应该提到 Express 有一个内置的功能,可以在路线之间共享数据。有一个名为 app.local 的对象。我们可以附加属性,并从我们的路线内访问它。您只需在 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'));

这个数据库连接现在可以在您的路由中访问,如下所示,而不需要创建和需要额外的模块。

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可以很容易地访问它,并且不需要额外的模块。

基于公认的答案,我使用了一个简单的方法。但是,只有当您想要使用 db内部函数时才使用这个函数,该函数将在一段时间后执行。对于 ex: 在快速路由函数中,这是您可以采用的最简单的方法。

Mongo.js

const MongoClient = require("mongodb").MongoClient


var db


const connectDb = (callback) => {
if (db) return callback()
MongoClient.connect( uri, {ops},
(err, database) => {
if (err) return console.log(err)
db = database.db("dbName")
console.log("Database Connected")
callback()
}
)
}


const getDb = (collectionToGet) => {
return db.collection(collectionToGet)
}


module.exports = {
connectDb,
getDb,
}

现在,在需要 db 对象的其他文件中,

User.js

const { connectDb, getDb } = require('mongo.js')


var db // store db object in this object
connectDb(() => ( db = getDb("user") ))


app.get('/', (req, res) => {
// do something with req
db.insert({})
// do something with res
}

您可以使用 单件设计模式实现 MongoDB 连接的跨文件使用。

Init.mjs

/* ################ Controller ################ */
import ctrlLib from '../../controller/lib.mjs';


/* ################ MongoDB ################ */
import mongodb from 'mongodb';


/* ################ Logs ################ */
import log from 'fancy-log';
import chalk from 'chalk';




/** Init MongoDB connection */
export class Init {
/**
* Check if its first time usage of this class.
If true set class instance to this that we always get same instance.
* Then get MongoDB details from config.yml and set as global.
* In the last step we return the class instance.
*/
constructor() {
if (Init.instance == null) Init.instance = this;


const config = ctrlLib.getConfig();
this.MongoURL = config.MongoDB.url;
this.MongoName = config.MongoDB.dbname;
({MongoClient: this.MongoClient} = mongodb);


return Init.instance;
}; // constructor(){




/** Connect to Database and return connection */
async connect() {
try {
const client = await this.MongoClient.connect(
this.MongoURL, {useNewUrlParser: true, useUnifiedTopology: true},
);


this.connection = {'db': client.db(this.MongoName), 'client': client};
return this.connection;
} // try {
catch (e) {
log( `${chalk.red.bold('❌ ERROR')} while try to connect to MongoDB DB
${chalk.white.bold('Error:\n')} ${e}` );
} // catch (e) {
}; // async connect() {




/**
* Return connection for cross file usage
* @return {object}
*/
getConnection() {return this.connection;};
}; // export class Init {

App.mjs

  • 确保在项目内的任何地方创建 MongoDB 连接,以便稍后在其他文件中使用。
/* ################ Services ################ */
import {Init} from './Init.mjs';


(async ()=>{
await new Init().connect();
})().catch(e=>{log('app.mjs - Catch error: ' + e);});

任何其他文件。 mjs

/* ################ Services ################ */
import {Init} from './Init.mjs';


/** Subclass of Search which contains lib functions */
class Lib {
/**
* Find data by using search query and return result.
* @param {string} collection - Name of collection
* @param {object} query - Search query
*/
async findOne(collection, query) {
const connection = new Init().getConnection();
return await connection.db.collection(collection).findOne(query);
}; // async findOne() {
}; // class Lib {


我试了“ go-oleg”的答案,效果还不错。在 getDb()中,我确保必须定义 _db。如果没有定义,我调用 connectToServer(),这样它就会被重新定义。在此之后,我不必调用 app.js中的 connectToServer(),这使我的代码干净。

let getDb = async() => {
if(_db) {
return _db
} else {
_db = await connectToServer()
return _db
}
}

然后,我简单地在任何地方调用 getDb()。而且,据我观察,第一通电话大概需要64毫秒。第一次通话后大约需要2-6毫秒。

我在这里回答是因为我的名声不好。

下面是一个使用 TypeScript 和 ES6特性和语法的建议:

Db.ts

import { Db, MongoClient } from 'mongodb'


let client: MongoClient
let db: Db


const connectToDatabase = async () => {
client = new MongoClient('databaseURI')
await client.connect()
db = client.db('dbname')
}


export {
connectToDatabase,
client,
db,
}


Index.ts

import express from 'express'
import { someRouter } from './routes/someRoute'
import { connectToDatabase } from './db'


connectToDatabase().then(() => {
const app = express()
app.use('/someRoute', someRouter)
const port = process.env.PORT || 5000
app.listen(port, () => {
console.log(`Server is listening on port ${port}`)
})
})

路线/部分路线

import express from 'express'
import { db } from '../db'


const someRouter = express.Router()


someRouter.route('/')
.get(async (req, res) => {
const results = await db.collection('collectionName').find().toArray()
return res.send(results)
})


export {
someRouter,
}

经过长时间的努力,我用这种操作方法工作: 请点击这个链接,这也是一个很好的解决方案: Https://mrvautin.com/re-use-mongodb-database-connection-in-routes/

2022年更新 MongoClient 新更新

Js (用于数据库连接和返回数据库实例)

const { MongoClient } = require('mongodb');
const uri = "your database connection url";
var _db;


module.exports = {
connectToServer: function (callback) {
MongoClient.connect(uri, { useNewUrlParser: true }, function (err, client) {
_db = client.db('testdb');
return callback(err);
});
},


getDb: function () { //this returns database instance
return _db;
}
};

Js (可以通过导入 mongoUtil 在任何路由或 js 中使用)

var mongoUtil = require('./mongoUtil');


mongoUtil.connectToServer(function (err, client) {
if (err) console.log(err);
console.log(`server is running`);


insertData(); //or do functions and db queries in any js


});


async function insertData() { //Functions should be async
var database = mongoUtil.getDb();
var movies = database.collection('movies');


const doc = {
title: "Movie title",
content: "Movie content",
}


const result = await movies.insertOne(doc);
console.log(`A document was inserted with the _id: ${result.insertedId}`);
}

伙计们,在2022年不需要重新连接逻辑,Node.js MongoDB 驱动程序为您处理这一切(v4 +)。

您可以简单地按照官方文档中的描述进行连接。把它放到 db.js 文件中,然后你就可以在应用程序的任何地方导入 client 或 db:

import { MongoClient, ServerApiVersion } from 'mongodb'
const uri = `mongodb+srv://...`;


// Create a new MongoClient
export const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 });


export const db = client.db('your_db');

在进行查询时,使用 try/catch 捕获潜在的连接错误。

try {
const res = await db.collection("testdata").insertOne({test: Math.random()});
console.log('Inserted', res);
} catch(e) {
console.error('MONGO ERROR', e);
}

AFAIK,如果连接丢失,Mongo 驱动程序将永远重试。

自己试试: 把上面的代码放在 setInterval 中,关闭一会儿互联网连接,然后再打开它,Mongo 会自动重新连接,即使在停机数小时之后。它甚至会提交一些在连接中断时提出的查询。