以前我用mongodb和php一起查询我使用单例的数据库。这样我只实例化一次连接,然后重复使用它:
class MDB{
protected static $instance;
public static function use(){
if(!self::$instance) self::$instance = new MongoClient();
$db = self::$instance->selectDB('DB_name');
return $db;
}
}
我可以创建类Cats,并使用类似的方法添加addCat和showCats方法:
MDB::use->{'cats'}->insert([...]);
MDB::use->{'cats'}->find([...]);
现在我开始在node.js中使用mongodb。 Mongodb tutorial向我展示了这样的事情:
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);
});
这基本上告诉我,我必须将所有节点操作设置为connect内部的回调。阅读该人提供的类似question:
当您的应用启动并重复使用时,您可以打开一次MongoClient.connect db对象。它不是每个单独的连接池.connect 创建一个新的连接池。
但是我无法理解我应该如何使用它(例如我的猫类)?
答案 0 :(得分:10)
这是一种方法。您可以将数据库连接详细信息放在一个小模块中,在应用程序启动时对其进行初始化,然后从需要数据库连接的任何其他模块中使用该模块。这是我一直在使用的代码,并且在一个相当简单的内部应用程序中为我工作。
文件: 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);
}
然后从server.js开始,当你的应用程序启动时:
// Startup database connection
require('./DataAccessAdapter').InitDB();
当您需要使用数据库时,例如在“ 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);
}
});
}
我希望这对于看到不同的方法至少有点帮助。我并不认为自己是专家,并对此提出了一些反馈意见,但到目前为止,这个解决方案对我来说效果很好。
答案 1 :(得分:7)
我赞成了Scampbell的解决方案,但他的解决方案应该加强imho。
目前它不是异步的,InitDB
和GetDB()
都应该有回调属性。
因此,每当您将数据库更改为连接时,它都会失败,因为它会在有机会连接到数据库之前返回。
如果始终连接到同一数据库,则该错误不存在(因此返回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);}
}
});
};
其余的功能也是如此。另请注意if (callback
部分,它允许在app.js / server.js的开头无需参数调用Database.InitDB()
,无论您的主文件是什么。
((我应该把我的回复写成对Scampbell解决方案的评论,但我没有足够的声誉这样做。同样对他的解决方案赞不绝口,这是一个很好的起点) )
答案 2 :(得分:5)
以下是在singleton上使用async await的内容。 在我的 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();
在所有将使用相同连接的模块中
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;
}
}
答案 3 :(得分:1)
我使用打字稿连接到 node.js 中的 mongodb 的单例类的完整工作示例。
import {Db, MongoClient, MongoError} from 'mongodb'
// Connexion credentials type
type MongoDBCredential = {
dbName: string;
username: string,
password: string;
cluster: string;
}
// Singleton DBInstance Class
export class DbInstance {
private static _instance: DbInstance;
private _database: Db;
private _dbClient: MongoClient;
private constructor() {};
public static async getInstance(cred: Readonly<MongoDBCredential>): Promise<DbInstance> {
return new Promise((resolve, reject) => {
if(this._instance) {
resolve(this._instance);
}
this._instance = new DbInstance();
this._instance._dbClient = new MongoClient(`mongodb+srv://${cred.username}:${cred.password}@${cred.cluster}.mongodb.net/${cred.dbName}?retryWrites=true&w=majority&readPreference=secondary`, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
this._instance._dbClient.connect((error: MongoError) => {
if(error) {
reject(error);
}
this._instance._database = this._instance._dbClient.db(cred.dbName);
resolve(this._instance);
});
});
}
get db(): Db {
return DbInstance._instance._database;
}
get client(): MongoClient {
return DbInstance._instance._dbClient;
}
}
// To use it
const cred : MongoDBCredential = { dbName: '***', username: '***', password: '***', cluster: '***' };
DbInstance.getInstance(cred).then((dbi: DbInstance) => {
// do your crud operations with dbi.db
dbi.db.collection('employee').findOne({'salary': '80K€ ?'}).then(account => {
console.info(account);
dbi.client.close().
});
}).catch((error: MongoError )=> console.error(error));
答案 4 :(得分:0)
您可以使用ES6类来制作真正的Singleton。
以下是打字稿中的一个示例:
import { MongoClient } from "mongodb";
class MongoSingleton {
private static mongoClient: MongoClient;
static isInitialized(): boolean {
return this.mongoClient !== undefined;
}
static getClient(): MongoClient {
if (this.isInitialized()) return this.mongoClient;
// Initialize the connection.
this.mongoClient = new MongoClient(mongoUri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
return this.mongoClient;
}
您可以改进该类,以在内部连接并保持连接,或在其他类中连接和断开连接。