Async Await and Shareable MongoDB connection

I am currently working on building a backend using Express and MongoDB Native Node. I have been researching attempting to find the best "best practice" for managing connections to a Mongo database and using that connection across the app. My current solution is working and I get desired results via tests in Postman. I have come up with this after being unable to find concrete answers on handling the connections with MongoDB 3.x (without Mongoose) and still modular.

Would someone be willing to give some feedback on my current solution?

My main concern would be that this setup would not be performant. I suspect it may not be, potentially due to opening/closing connections frequently, but I am not sure if the way I am doing it is good or bad practice.

I created a db.js file to serve my connection:

const assert = require("assert");
const MongoClient = require("mongodb").MongoClient;
const base = process.env.PWD;
const config = require(base + "/config");
let db;
let client;


const connect = async () => {
  const url = config.url
  const dbName = config.dbName
  client = await MongoClient.connect(url)
  db = await client.db(dbName)
  return db
}

const disconnect = () => {
  client.close()
}

module.exports = {
  connect: connect,
  disconnect: disconnect
  }

I then set the routes for my 'todos' in index.js inside of my todos folder. Following a best practice suggestion to have all component files in their own folders(open to feedback on folder structure):

const express = require('express'),
base = process.env.PWD,
router = express.Router(),
todos = require(base + '/todos/todosController')

/* GET All Todos */
router.get('/all', todos.getTodos)
/* GET One Todo */
router.get('/todo/:id', todos.getTodo)
/* POST One Todo */
router.post('/todo/:id', todos.addTodo)
/* DELETE One Todo */
router.delete('/todo/:id', todos.deleteTodo)

module.exports = router;

Lastly the actual todosController.js which requires db.js This is where I suspect some improvement could happen but I am just not sure. I connect within the routes via async function and await the connection and assign it to db I do my CRUD queries (all currently working properly) and then disconnect at the end. If this is considered performant and a good practice I am happy with that answer but if there is a way to do this better with current driver and syntax I would be happy for any feedback.

'use strict';

const base = process.env.PWD,
      client = require(base + '/db.js'),
      assert = require('assert')

let db

const getTodos = async (req, res) => {
  db = await client.connect()
  const collection = await db.collection('documents')
  // Find all todos
  collection.find({}).toArray((err, todos) => {
    assert.equal(err, null)
    res.status(200).json(todos)
  })
  client.disconnect()
}

1 answer

  • answered 2018-11-07 23:39 Akrion

    It seems that this is a common misconception that opening and closing a connection on every request is more efficient. Opening connection is expensive and this is one of the reasons for the existence of the connection pools. MongoDB supports those and you should consider them.

    Here is an article on the subject of Express/MongoDB connection handling which starts right away with:

    A common mistake developers make when connecting to the database is to call MongoClient.connect() in every route handler to get a database connection.