我在express.js app中使用mongodb-native-driver。我在数据库中有大约6个集合,所以我创建了6个js文件,每个文件都有一个集合作为javascript对象(例如function collection(){}
),原型函数处理这些集合上的所有操作。我认为这将是一个很好的架构。
但我遇到的问题是如何连接到数据库?我应该在每个文件中创建一个连接并使用它们吗?我认为这将是一种过度杀伤,因为mongodb-native-driver中的连接会创建一个连接池,并且其中有几个连接不合理。
那么我如何创建一个连接池并在所有collections.js文件中使用它?我想要像在mongoose中实现的那样建立连接。如果我在应用程序架构中的任何思维过程都是错误的,请告诉我。
使用Mongoose可以解决这些问题,但我在几个地方读过它比本机驱动程序慢,而且我更喜欢无架构模型。
编辑我用模型创建了一个模块。每个集合都在一个文件中,它将数据库作为参数。现在在index.js文件中,我调用数据库连接并在从连接获取数据库后保留变量db。 (我使用了自动重新连接功能来确保连接没有丢失)。在同一个index.js文件中,我像这样导出了每个集合
exports.model1 = require('./model1').(db)
exprorts.model2 = require('./model2').(db)
这确保了数据库部分只在一个模块中处理,应用程序只调用每个model.js文件导出的函数,如save()
,fincdbyid()
等(whatever you do in the function is upto you to implement
)。
答案 0 :(得分:18)
如何连接数据库?
要使用MongoDB本机驱动程序进行连接,您需要执行以下操作:
var util = require('util');
var mongodb = require('mongodb');
var client = mongodb.MongoClient;
var auth = {
user: 'username',
pass: 'password',
host: 'hostname',
port: 1337,
name: 'databaseName'
};
var uri = util.format('mongodb://%s:%s@%s:%d/%s',
auth.user, auth.pass, auth.host, auth.port, auth.name);
/** Connect to the Mongo database at the URI using the client */
client.connect(uri, { auto_reconnect: true }, function (err, database) {
if (err) throw err;
else if (!database) console.log('Unknown error connecting to database');
else {
console.log('Connected to MongoDB database server at:');
console.log('\n\t%s\n', uri);
// Create or access collections, etc here using the database object
}
});
基本连接是这样设置的。这就是我可以给你的所有内容,只是你想要的基本描述。发布到目前为止您已获得的一些代码,以获得更具体的帮助。
我应该在每个文件中创建连接并使用它们吗?
没有
那么如何创建单个连接池并在所有collections.js文件中使用它?
您可以使用上面的代码创建单个文件,让我们将其称为dbmanager.js
连接到数据库。导出在您的数据库上运行的createUser
,deleteUser
等函数,然后导出如下函数:
module.exports = {
createUser: function () { ; },
deleteUser: function () { ; }
};
然后你可以从另一个文件中require
这样:
var dbman = require('./dbmanager');
dbman.createUser(userData); // using connection established in `dbmanager.js`
编辑:因为我们正在处理JavaScript和单个线程,所以本机驱动程序确实会自动为您处理连接池。您可以在下面的StackOverflow链接中查找此信息,以便对此进行更多确认。 OP也在问题中说明了这一点。这意味着服务器实例只应将client.connect
称为 。通过调用database
成功检索到client.connect
对象后,应该在整个应用实例中重用该database
个对象。这可以通过使用Node.JS提供的模块模式轻松完成。
我的建议是创建一个模块或一组模块,作为与数据库交互的单一联系点。在我的应用程序中,我通常只有一个模块,它取决于本机驱动程序,调用require('mongodb')
。我的应用程序中的所有其他模块都不会直接访问数据库,而是所有操作都必须由此数据库模块协调。
这将处理本机驱动程序的所有代码封装到单个模块或模块集中。 OP似乎认为我发布的简单代码示例存在问题,在我的示例中描述了“单个大封闭”的问题。这都是非常基本的东西,所以我在这里添加了关于基本架构的说明,但我仍然觉得不需要更改任何代码。
OP似乎也认为可以在这里建立多个连接。这种设置无法做到这一点。如果您按照我的建议创建了一个模块,那么第一次调用require('./dbmanager')
时,它将执行文件dbmanager.js
中的代码,返回module.exports
对象。导出对象被缓存,并且在每次后续调用require('./dbmanager')
时也会返回,但dbmanager.js
中的代码只会在第一个require
执行。
如果您不想创建这样的模块,那么另一个选项是仅导出传递给database
回调的client.connect
,并直接在整个应用的不同位置使用它。无论OP如何关注,我都建议不要这样做。
类似的,可能重复的Stackoverflow问题,其中包括:
答案 1 :(得分:2)
正如已接受的答案所说 - 您应该只为所有传入请求创建一个连接并重复使用它,但是答案是缺少解决方案,这将创建并缓存连接。我写了快速中间件来实现这一点 - express-mongo-db。乍一看,这项任务很简单,大多数人都使用这种代码:
var db;
function createConnection(req, res, next) {
if (db) { req.db = db; next(); }
client.connect(uri, { auto_reconnect: true }, function (err, database) {
req.db = db = databse;
next();
});
}
app.use(createConnection);
但是当多个请求同时到达时,此代码会导致连接泄漏,并且db
未定义。 express-mongo-db
通过保留传入客户端并仅在需要模块时调用connect
一次来解决此问题(而不是在第一个请求到达时)。
希望你觉得它很有用。
答案 2 :(得分:0)
我只是想我会为自己感兴趣或有不同方法问题的人添加我自己的MongoDB连接方法
此方法假定您不需要身份验证(我在localhost上使用此方法)
身份验证仍然易于实施
var MongoClient = require('mongodb').MongoClient;
var Server = require('mongodb').Server;
var client = new MongoClient(new Server('localhost',27017,{
socketOptions: {connectTimeoutMS: 500},
poolSize:5,
auto_reconnect:true
}, {
numberOfRetries:3,
retryMilliseconds: 500
}));
client.open(function(err, client) {
if(err) {
console.log("Connection Failed Via Client Object.");
} else {
var db = client.db("theDbName");
if(db) {
console.log("Connected Via Client Object . . .");
db.logout(function(err,result) {
if(!err) {
console.log("Logged out successfully");
}
client.close();
console.log("Connection closed");
});
}
}
});
归功于Brad Davley,他在book(第231-232页)中讨论了这种方法