15

我在 express.js 应用程序中使用 mongodb-native-driver。我在数据库中有大约 6 个集合,所以我创建了 6 个 js 文件,每个文件都有一个作为 javascript 对象的集合(例如function collection(){}),原型函数处理对这些集合的所有操作。我认为这将是一个很好的架构。

但是我遇到的问题是如何连接到数据库?我应该在每个文件中创建一个连接并使用它们吗?我认为这将是一种矫枉过正,因为 mongodb-native-driver 中的连接创建了一个连接池,并且拥有其中几个连接是不合理的。

那么如何创建单个连接池并在所有 collections.js 文件中使用它呢?我想要像在猫鼬中实现的那样的连接。如果我在应用程序架构中的任何思考过程是错误的,请告诉我。

使用 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)。

4

3 回答 3

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 问题,其中包括:

于 2013-08-04T21:39:13.257 回答
2

正如接受的答案所说 - 您应该为所有传入请求只创建一个连接并重用它,但答案缺少解决方案,它将创建和缓存连接。我写了 express 中间件来实现这个 - 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

希望你觉得它有用。

于 2014-08-08T18:43:00.073 回答
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,他在他的书中(第 231-232 页)介绍了这种方法

于 2014-08-21T01:52:28.597 回答