与node.js和mongo建立单例连接

Sal*_*ali 10 mongodb node.js

以前我用php使用mongodb并查询我使用单例的数据库.这样我只实例化一次连接然后重用它:

class MDB{
    protected static $instance;
    public static function use(){
        if(!self::$instance) self::$instance = new MongoClient();
        $db = self::$instance->selectDB('DB_name');
        return $db;
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以创建类Cats,并使用类似这样的方法addCat和showCats:

MDB::use->{'cats'}->insert([...]);
MDB::use->{'cats'}->find([...]);
Run Code Online (Sandbox Code Playgroud)

现在我开始使用mongodb和node.js. Mongodb教程给我看了这样的事情:

var MongoClient = require('mongodb').MongoClient;
MongoClient.connect("mongodb://localhost:27017/exampleDb", function(err, db) {
  if(err) { return console.dir(err); }

  var collection = db.collection('test');
  var doc1 = {'hello':'doc1'};
  collection.insert(doc1);
});
Run Code Online (Sandbox Code Playgroud)

这基本上告诉我,我必须将所有节点操作设置为connect内部的回调.阅读该人提供的类似问题:

当您的应用程序启动并重用db对象时,您可以打开一次MongoClient.connect.它不是单独的连接池,每个.connect都会创建一个新的连接池.

但我无法理解我应该如何使用它(例如我的猫类)?

Sca*_*ell 11

这是一种方法.您可以将数据库连接详细信息放在一个小模块中,在应用程序启动时对其进行初始化,然后从需要数据库连接的任何其他模块中使用该模块.这是我一直在使用的代码,并且在一个相当简单的内部应用程序中为我工作.

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);
}
Run Code Online (Sandbox Code Playgroud)

然后从server.js开始,当你的应用程序启动时:

// Startup database connection
require('./DataAccessAdapter').InitDB();
Run Code Online (Sandbox Code Playgroud)

当您需要使用数据库时,例如在" Cat.js "文件中,您可以执行以下操作:

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);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

我希望这对于看到不同的方法至少有点帮助.我并不认为自己是专家,并且对此有一些反馈意见,但到目前为止,这个解决方案对我来说效果很好.


arc*_*col 8

我赞成了Scampbell的解决方案,但他的解决方案应该加强imho.目前,它不是异步,两者InitDBGetDB()应该有一个回调的属性.

因此,每当您将数据库更改为连接时,它都会失败,因为它会在有机会连接到数据库之前返回.如果始终连接到同一数据库,则该错误不存在(因此返回Database.db始终成功)

这是我对他的解决方案的错误修正/增强:

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);}
    }
  });
};
Run Code Online (Sandbox Code Playgroud)

他的其他职能也是如此.还要注意if (callback部分,它允许Database.InitDB()在app.js/server.js的开头无需参数调用,无论你的主文件是什么.

((我应该把我的回复写成对Scampbell解决方案的评论,但我没有足够的声誉这样做.同样对他的解决方案感到荣幸,这是一个不错的起点))


Ale*_*der 8

这是在singleton上使用async等待的内容.在我的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();
Run Code Online (Sandbox Code Playgroud)

并且在所有将使用相同连接的模块中

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;
    }
}
Run Code Online (Sandbox Code Playgroud)