MisterniceGuy
MisterniceGuy

Reputation: 1796

How to reuse Db Connections in Nodejs and Express

I am wondering what the best way is to reuse db connections in my case its couchebase connection in NodeJs as well as express. For the Express part i created a middleware like this

var couchbase = require('couchbase')
var config = require('../config/config')

module.exports = (req,res,next)=>{
  var cluster = new couchbase.Cluster(config.cluster)
  cluster.authenticate(config.userid, config.password)
  let bucket = cluster.openBucket(config.bucket);
  bucket.manager().createPrimaryIndex(function() {});
  req.bucket = bucket;
  req.N1qlQuery = couchbase.N1qlQuery;
  next();
}

which works fine in the express app since i tell it to

const dbSessionMiddleware = require('../middleware/couch')
app.use(dbSessionMiddleware) 

which allows me to access it via req.bucket . My issue is that i have controllers in my app which in case might call a helper function and they might call another function to get some data back. I want to avoid to have to keep passing the request object down 5 levels or so to use the middleware. Is there a better way how i can expose the connection / bucket to normal functions ?

Upvotes: 4

Views: 2409

Answers (2)

Drowsy
Drowsy

Reputation: 358

Have you tried taking your init code out of the middleware function? The Couchbase Documentation doesn't show it being used that way. Albeit the example is in vanilla Node. By placing it in a middleware function, you're going to be re-connecting to your database everytime the server receives a request.

I connect to my Mongo server in top-level app.js body, which allows the connection to persist. Then I can just import the mongoose reference I need in my Models and Controller to outline how to fetch certain data, and then call the controller's method inside the relevant route endpoint.

Edited to show an example of assigning bucket as a controller class field

In your app.js

const couchbase = require("couchbase");
const config = require("../config/config");

// ...app.js

const CouchController = require("../controllers/CouchController")(couchbase, config);

// app.js...

In your controller

class CouchController {

  constructor(couchbase, config) {
    // You may either pass couchbase and config as params, or import directly into the controller
    this.cluster = new couchbase.Cluster(config.cluster);
    this.cluster.authenticate(config.userid, config.password);
    this.bucket = cluster.openBucket(config.bucket);
    this.N1qlQuery = couchbase.N1qlQuery;
  }

  doSomeQuery(queryString, callback) {

    // Use your query however its meant to be used. I'm not familiar with couchbase queries.
    this.bucket.manager().createPrimaryIndex(function() {

      this.bucket.query(
        this.N1qlQuery.fromString("SELECT * FROM bucketname WHERE $1 in interests LIMIT 1"),
        [queryString],
        callback(err, result)
      )

    });
  }

}

Then call your Controller method from inside a route

router.get("/", function(req, res, next) {

  let searchParam = req.query.someParam;

  CouchController.doSomeQuery(searchParam)
    .then(result => {
      res.json(result);
    });

});

Upvotes: 3

Joilson Cisne
Joilson Cisne

Reputation: 187

You could create a specialized module (e.g. db.js) where you would implement a singleton for you pool of connections.

// pseudo-code
export const getDb = () => {
  let db

  if (!db) {
    const connection = createConnectionPool()
    db = connection.db
  }

  return db
}

This function could be imported on your middleware and on other parts of your code.

Upvotes: 1

Related Questions