1

I'm developing a node.js app and I'm passing mongoDB into functions, so it is easier to unit test, as I can mock my production mongoDB with a test mongoDB database. However, I am not sure I'm doing it correctly as I think I might be creating multiple client instances;

//db.js

import mongodb from 'mongodb';

export default async function makeDb() {
  const { MongoClient } = mongodb;
  const url = process.env.DB_URL;
  const client = new MongoClient(url,
    {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    });
  await client.connect();
  const db = await client.db('myDB');
  return db;
}

and then I import the makeDB function and pass it into multiple dbHandlers;

//authHandler.js

import makeDB from './db'

export default function dbMethods({ makeDB }) {
  const signup = async (username, password) => {
    const db = await makeDB();
    const result = await db
      .collection('users')
      .insertOne({ username, password });

    return result;
  };

  // other methods that also use const db = await makeDB();

  return Object.freeze({
    signup,
    // other methods
  });
}

Apart from the authHandler, I have also other handlers in my application that use the same technique.

Am I creating dozens of mongoDB client instances every time I do const db = makeDB()? If so, is there a better way of doing it

Oliver Wagner
  • 170
  • 2
  • 10
  • I just found this answer https://stackoverflow.com/a/44612321/5330655 to use express-mongo-db middleware with your express application – Rebai Ahmed Jun 18 '20 at 08:39
  • You create a new db connection on every db operation (dbMethods) which can cause performance. Either use a singleton connection by caching (@Shihab's solution), or simply export `db` (non-function) from `db.js` and consume it directly. Node.js caches all `require/import` so you can be sure you have only one single `db` instance. – Son Nguyen Jun 18 '20 at 09:00
  • 1
    @RebaiAhmed But using that package prevents me from injecting the database, which defeats the purpose of what I'm trying to do. Let's say I want to migrate to some other database in the future, then I would have to completely rewrite my application rather than just changing the db.js file – Oliver Wagner Jun 18 '20 at 09:30

1 Answers1

1

Yes, you are creating multiple DB clients. You can avoid it like this:

let client;
export default async function makeDb() {
  const { MongoClient } = mongodb;
  const url = process.env.DB_URL;

  if (!client) {
    client = new MongoClient(url,
      {
        useNewUrlParser: true,
        useUnifiedTopology: true,
      });
    await client.connect();
  }

  const db = await client.db('myDB');
  return db;
}
Shihab
  • 2,641
  • 3
  • 21
  • 29
  • Thanks for your answer and that makes sense as the client is only being instanced once by using the if statement. However, after the if statement, the `await client.db('myDB')` is always being returned. Does that mean that I'm still creating lots of db instances? – Oliver Wagner Jun 18 '20 at 09:25
  • As far as I can remember `.db()` is a synchronous function. You don't need to await it. Also, the value of `db('myDB')` is cached. So, even if you call it multiple times it should return the same value. – Shihab Jun 18 '20 at 09:35