DEV Community

Rodel Talampas
Rodel Talampas

Posted on

Singleton Connection with Transactions in MongoDB

I was looking at some patterns on how to use MongoDB Transactions but I want it to be a common wrapper and should be simple enough for nodejs beginners (like me) to understand. I saw some functions accepting another, function with multiple parameters, as a parameter, but you need to take care of overloading cases.

Thinking of a simple solution, why not just wrap all arguments into a single variable like a map. This may not work for others but certainly works on our case.

First, I need to make sure that I only have 1 DB Connection always. Hence I created a Singleton class.

const mongoose = require('mongoose');
...
...

// Define Singleton DB Connection Class
class Connection {
  constructor() {
    if (!Connection.instance) {
      mongoose.connect(config.mongoose.url, config.mongoose.options);
      this.conn = mongoose.connection;
      this.conn.on('error', () => logger.error.bind(console, 'connection error'));
      this.conn.on('open', () => logger.info(`Connected to MongoDB ${config.mongoose.url} for Transaction...`));
    }
  }
}

module.exports = new Connection();
Enter fullscreen mode Exit fullscreen mode

I will use this class in every part of my systems and it will ensure that I won't be having multiple cases of DB connection.

Now to create a transaction wrapper, I do this. This is a self-managed transaction meaning I dont need to call commit and rollback. But if you want to manually handle each commit and rollback, you may do so here as well.

const db = require('./connection');

const withTransaction = async (fn) => async (map) => {
  const session = await db.conn.startSession();
  await session.withTransaction(fn(map), { session });
  session.endSession();
};

module.exports = withTransaction;
Enter fullscreen mode Exit fullscreen mode

To call do something like this:

async function saveFunction(map) {
  //.. implementation
  const { var1, var2 } = map;
  // use the var1, var2 here ....
  // call mongodb CRUD here 
}

// service call
const save = async (map) => {
  withTransaction(saveFunction(map));
};
Enter fullscreen mode Exit fullscreen mode

Hoping to get some comments so that I can improve this wrapper in the future.

Top comments (0)