4

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 ?

2 Answers 2

3

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);
    });

});
Sign up to request clarification or add additional context in comments.

2 Comments

I get the controller / route part as i use it already. What i am not clear on is how do i access the defined bucket from controller as i need the bucket to make the actual call
You could assign the bucket variable as a field in the controllers constructor. Then you would import the controller into your app.js and instantiate it with all of your other init code. To give the constructor a reference to your couch base connection you could either do that in the constructor as well, or initialize it in app.js and pass it to the constructor as a parameter.
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.