Previously I used mongodb with php and to query a database I was using a singleton. This way I instantiated connection only once and then reused it:
class MD
Here's one way to do it. You can put your database connection details in a small module, initialize it when your app starts up, then use that module from any other modules that need a database connection. Here's the code I've been using and has been working for me in a rather simple internal application.
file: DataAccessAdapter.js
var Db = require('mongodb').Db;
var Server = require('mongodb').Server;
var dbPort = 27017;
var dbHost = 'localhost';
var dbName = 'CatDatabase';
var DataBase = function () {
};
module.exports = DataBase;
DataBase.GetDB = function () {
if (typeof DataBase.db === 'undefined') {
DataBase.InitDB();
}
return DataBase.db;
}
DataBase.InitDB = function () {
DataBase.db = new Db(dbName, new Server(dbHost, dbPort, {}, {}), { safe: false, auto_reconnect: true });
DataBase.db.open(function (e, d) {
if (e) {
console.log(e);
} else {
console.log('connected to database :: ' + dbName);
}
});
}
DataBase.Disconnect = function () {
if (DataBase.db) {
DataBase.db.close();
}
}
DataBase.BsonIdFromString = function (id) {
var mongo = require('mongodb');
var BSON = mongo.BSONPure;
return new BSON.ObjectID(id);
}
Then from server.js, when your application is starting up:
// Startup database connection
require('./DataAccessAdapter').InitDB();
And when you need to use the database, for example in your "Cat.js" file, you could do something like this:
var dataAccessAdapter = require('./DataAccessAdapter');
var Cat = function () {
if (!Cat.db) {
console.log('Initializing my Cat database');
Cat.db = dataAccessAdapter.GetDB();
}
if (!Cat.CatCollection) {
console.log('Initializing cats collection');
Cat.CatCollection = Cat.db.collection('Cats'); // Name of collection in mongo
}
return Cat;
}
module.exports = Cat;
Cat.Name = null;
Cat.HasFur = false;
Cat.Read = function (catId, callback) {
var o_id = dataAccessAdapter.BsonIdFromString(catId);
Cat.CatCollection.findOne({ '_id': o_id }, function (err, document) {
if (!document) {
var msg = "This cat is not in the database";
console.warn(msg);
callback(null, msg);
}
else {
callback(document);
}
});
}
I hope this is at least a little helpful in seeing a different approach. I don't claim to be an expert and am open to some SO feedback on this, but this solution has worked well for me so far.
I upvoted Scampbell's solution, but his solution should be enhanced imho.
Currently it is not async, both InitDB
and GetDB()
should have a callback attribute.
So whenever you change a database to connect, it fails, because it returns before it would have a chance to connect to the database.
The bug is not present if you connect always to the same database (so return Database.db
is always successful)
This is my bugfix/enhancement to his solution:
Database.InitDB = function (callback) {
if (_curDB === null || _curDB === undefined ||_curDB === '') {
_curDB = _dbName;
}
Database.db = new Db(_curDB,
new Server(_dbHost, _dbPort, {}, {}),
{ safe: false, auto_reconnect: true });
Database.db.open(function (err, db) {
if (err) {
console.log(err);
} else {
console.log('connected to database :: ' + _curDB);
if (callback !== undefined) {callback(db);}
}
});
};
The same goes to the rest of his functions. Also note the if (callback
part, it allows Database.InitDB()
to be called without argument in the beginning of app.js/server.js whatever is your main file.
((I should have written my reply as a comment to Scampbell's solution, but I don't have enough reputation to do so. Also kudos to him for his solution, was a nice starting point))
Here is what uses async await on singleton. In my db.js
var MongoClient = require('mongodb').MongoClient;
var DbConnection = function () {
var db = null;
var instance = 0;
async function DbConnect() {
try {
let url = 'mongodb://myurl.blablabla';
let _db = await MongoClient.connect(url);
return _db
} catch (e) {
return e;
}
}
async function Get() {
try {
instance++; // this is just to count how many times our singleton is called.
console.log(`DbConnection called ${instance} times`);
if (db != null) {
console.log(`db connection is already alive`);
return db;
} else {
console.log(`getting new db connection`);
db = await DbConnect();
return db;
}
} catch (e) {
return e;
}
}
return {
Get: Get
}
}
module.exports = DbConnection();
And in all modules that will use the same connection
var DbConnection = require('./db');
async function insert(data) {
try {
let db = await DbConnection.Get();
let result = await db.collection('mycollection').insert(data);
return result;
} catch (e) {
return e;
}
}