Setting up singleton connection with node.js and mongo

前端 未结 3 1358
北荒
北荒 2020-12-02 21:57

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         


        
相关标签:
3条回答
  • 2020-12-02 22:13

    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.

    0 讨论(0)
  • 2020-12-02 22:21

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

    0 讨论(0)
  • 2020-12-02 22:24

    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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题