0

Currently working on a backend in nodeJS which uses express,socket.io, and has MongoDB as its database. I read that it is a good practice to implement a singleton DB connection which is to be reused in the entire application. I tried to implement this didn't find a solution yet. I tried to use this SO answer of go-oleg.

I replicated the first part, the external mongoUtil.js file like this:

var MongoClient = require( 'mongodb' ).MongoClient;

var _db;

module.exports = {

  connectToServer: function( callback ) {
    MongoClient.connect( "mongodb://localhost:27017/marankings", function( err, db ) {
      _db = db;
      return callback( err );
    } );
  },

  getDb: function() {
    return _db;
  }
};

Then in my server.js I call this function once like this (I don't do anything with the callback is this required?).

var mongoUtil = require( 'mongoUtil' );

mongoUtil.connectToServer( function( err ) {
  // start the rest of your app here
} );

then when I tried the following in another module of the application:

const db = mongoDB.getDb();

router.post('/', (req, res, next) => {
    console.log(db);
    next();
})

Logs undefined

The log says undefined and thus I dont have a DB instance.

Question:

Why isn't this working and how can I solve this issue?

3
  • I managed to solve this on a personal project, but I did not know myself if it was a best practice... my code is using ecmascript 6.0 standard... if you're interested... I can put pieces of it... Commented May 8, 2018 at 17:02
  • 1
    Too many problems. Try some up-to-date tutorials. The answer you are referring to assumes some basic experience with node and is unfortunately outdated. MongoClient.connect returns client, not db since v3 of the driver. Commented May 8, 2018 at 17:03
  • Yes I would appreaciate that, thanks! Commented May 8, 2018 at 17:03

1 Answer 1

1

Ok... so, this is could be using a bit of outdated use of Mongo, but this is how I managed to solve the singleton piece of the DB. Disclaimer: it was a personal learning project for Mongo and Ecmascript 6.0 so not sure it follows the Best practices, but it works.

Fist, Db Connection: personnaDB.js

/************  Copyright ************/
/* Year: 2016
 * Author: David Espino
*/
"use strict"
// Imports
const url             = require('url'),
      connectionUrl   = process.env.CONNECTION_STRING || 'mongodb://localhost:27017/personna',
      parsedUrl       = url.parse(connectionUrl),
      Db              = require('mongodb').Db,
      Server          = require('mongodb').Server,
      Connection      = require('mongodb').Connection,
      Q               = require("q"),
      mongoose        = require("mongoose"),
      dao             = require('./personnaDao'),
      autoIncrement   = require( 'mongoose-auto-increment' );



// Symbol Keys
const _connKey = Symbol();
const _connInfoKey = Symbol();
const _monConnKey = Symbol();
const _dataModelsKey = Symbol();
const _autoIncrementKey = Symbol();

/**
 * This class represents the DB Connection
 */
class PersonnaDb {
  /**
   * Class Constructor
   * @return {[type]} [description]
   */
  constructor() {
    let mongoObject = null;
    this[_connInfoKey] = {
      host:     parsedUrl.hostname,
      port:     parseInt(parsedUrl.port, 10),
      name:     parsedUrl.pathname.substr(1),
      user:     parsedUrl.auth ? parsedUrl.auth.split(':')[0] : null,
      password: parsedUrl.auth ? parsedUrl.auth.split(':')[1] : null
    };
    this._connInstance = null;
  }

  /**
   * Opens the DB connection using regular mongo db access
   * @return {[type]} [description]
   */
  openConnection() {
    let deferred = Q.defer();
    if (this[_connKey]) {
      console.log('---> not need to create instance');
      deferred.resolve(this[_connInfoKey]);
    } else {
      let $this = this;
      const mongoObject = new Db('your-db', new Server(this[_connInfoKey].host, this[_connInfoKey].port, { auto_reconnect: true }));
      mongoObject.open(function(error, databaseConnection) {
        if (error) throw new Error(error);
        console.log('---> Succesfully CREATED connection');
        $this[_connKey] = databaseConnection;
        // Initialize auto increment
        autoIncrement.initialize(databaseConnection);
        $this[_autoIncrementKey] = autoIncrement;
        deferred.resolve($this);
      });
    }
    return deferred.promise;
  } 

  /**
   * Opens a Mongo db connection
   * @return {[type]} [description]
   */
  openMongooseConnection() {
    mongoose.connect(connectionUrl); 
    // set the identity plugin
    autoIncrement.initialize(mongoose.connection);
    this[_autoIncrementKey] = autoIncrement;

    // CONNECTION EVENTS
    // When successfully connected
    mongoose.connection.on('connected', function () {  
      console.log('Mongoose default connection open to ' + parsedUrl);
    }); 

    // If the connection throws an error
    mongoose.connection.on('error',function (err) {
      console.log('Mongoose default connection error: ' + err);
    });

    // When the connection is disconnected
    mongoose.connection.on('disconnected', function () {
      console.log('Mongoose default connection disconnected');
    });

    // If the Node process ends, close the Mongoose connection
    process.on('SIGINT', function() {
      mongoose.connection.close(function () {
        console.log('Mongoose default connection disconnected through app termination');
        process.exit(0);
      });
    });

    this[_dataModelsKey] = dao.PersonaDataModels.GetModels(this[_autoIncrementKey]);
   // require('../models/data/bodySectionModel');
  }

  dataModels() {
    return this[_dataModelsKey];
  }
}

module.exports.PersonnaDb = PersonnaDb;

Second... services setup (my layer that takes the dbconnection)

services > include.js

const ModifierService  = require('./modifierService').ModifierService;
const BodySectionService  = require('./bodySectionService').BodySectionService;
module.exports = (dbConnection) => {
  return {
    Modifier: new ModifierService(dbConnection),
    BodySection: new BodySectionService(dbConnection),

  }
}

Sample of the service (it basically intitializes the mongo Model. BodySectionService.js

class BodySectionService extends BaseService {

  constructor(db) {
    super(db.dataModels().BodySection); // this is the mongo model with the schema etc
  }

Then DB initialization (and passing the DB Connection as a singleton object)

app.js

var express = require('express');
const PersonnaDb = require('./dao/personnaDb').PersonnaDb;
const dbConnection = new PersonnaDb();

var app = express();
// Open DB Connection
dbConnection.openMongooseConnection();
// get the services
const services = require('./services/include')(dbConnection);

// // This is the piece that I was not totally sure, making this available on the app
app.set('services', services);
app.set('dbAccess', dbConnection); 

And this is how I use it:

bodySectionController.js

router.get('/', function(req, res, next) {
  const bodySectionProxy = req.app.get("services").BodySection;
  const logger = req.app.get("customLogger");
  var result = bodySectionProxy.getBodySections({}).then((result) => {
    res.json(result);
  })
  .fail((err) => {
    logger.logError(err);
    res.json(err.message);
  })
  .done();
});

module.exports = router;

I've excluded the Path on how I set the models on the service since your question only asks about How to setup the DB. But if you need me to, I could extend the answer with that too.

Hope this gives an idea.

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.