-1

我正在寻找一个包(或模式)来处理来自 mongodb 的事件,这样我就可以避免嵌套回调并将 mongodb 逻辑排除在我的请求处理程序之外。

现在我的代码看起来像这样:

start-express.js(服务器)

var express = require('express');
var Resource = require('express-resource');
var app = express.createServer();

// create express-resource handler  which essentially does app.get('things', ...)
var things = app.resource('things', require('./things.js'));

app.listen(port);

things.js(快速资源请求处理程序)

require('./things-provider');

// handle request  'http://example.com/things'
exports.index = function(request, response) {
    sendThings(db, response);
};

things-provider.js(处理 mongodb 查询)

var mongodb = require('mongodb')

// create database connection
var server = new mongodb.Server(host, port, {auto_reconnect: true});
var db = new mongodb.Db(dbName, server);

db.open(function (err, db) {
    if (err) { }
    // auto_reconnect will reopen connection when needed
});

function sendThings(db, response) {            
    db.collection('things', function(err, collection) {
        collection.find(function(err, cursor) {
            cursor.toArray(function(err, things) {
                response.send(things);
            });
        });
    });
}

module.exports.sendThings = sendThings;

我想避免将我的 http 响应对象传递给我的数据库处理程序,或者(更糟)在我的 http 响应处理程序中处理我的 db 请求。

我最近意识到我想要做的是创建一个事件处理程序,它注册一个 http 请求/响应并在处理和发送 http 响应之前等待来自数据库的响应(事件)。

这听起来像是 node.js 已经做的很多重复。是否存在处理此用例的现有框架?

4

2 回答 2

2

这是我想出的解决方案。

我使用了 mongojs,它极大地简化了 mongodb 接口——以配置灵活性为代价——但它隐藏了 mongodb 驱动程序所需的嵌套回调。它还使语法更像 mongo 客户端。

然后我将 HTTP Response 对象包装在一个闭包中,并将这个闭包传递给回调中的 mongodb 查询方法。

var MongoProvider = require('./MongoProvider');
MongoProvider.setCollection('things');

exports.index = function(request, response){
    function sendResponse(err, data) {
        if (err) { 
            response.send(500, err);
        }    
        response.send(data);
    };

    MongoProvider.fetchAll(things, sendResponse);
};

它本质上仍然只是将响应对象传递给数据库提供程序,但是通过将它包装在一个知道如何处理响应的闭包中,它可以将该逻辑排除在我的数据库模块之外。

一个小小的改进是使用一个函数在我的请求处理程序之外创建一个响应处理程序闭包:

function makeSendResponse(response){
    return function sendResponse(err, data) {
        if (err) {
            console.warn(err);
            response.send(500, {error: err});
            return;
        }

        response.send(data);
    };
}

所以现在我的请求处理程序看起来像这样:

exports.index = function(request, response) {
    response.send(makeSendResponse(response));
}

我的 MongoProvider 看起来像这样:

var mongojs = require('mongojs');

MongoProvider = function(config) {
this.configure(config);
    this.db = mongojs.connect(this.url, this.collections);
}

MongoProvider.prototype.configure = function(config) {
    this.url = config.host + "/" + config.name;
    this.collections = config.collections;
}

MongoProvider.prototype.connect = function(url, collections) {
    return mongojs.connect(this.url, this.collections);
}

MongoProvider.prototype.fetchAll = function fetchAll(collection, callback) {
    this.db(collection).find(callback);
}

MongoProvider.prototype.fetchById = function fetchById(id, collection, callback) {
    var objectId = collection.db.bson_serializer.ObjectID.createFromHexString(id.toString());

    this.db(collection).findOne({ "_id": objectId }, callback);
}

MongoProvider.prototype.fetchMatches = function fetchMatches(json, collection, callback) {
    this.db(collection).find(Json.parse(json), callback);
}

module.exports = MongoProvider;

我还可以为特定集合扩展 MongoProvider 以简化 API 并进行额外的验证:

ThingsProvider = function(config) {
    this.collection = 'things';
    this.mongoProvider = new MongoProvider(config);
    things = mongoProvider.db.collection('things');
}

ThingsProvider.prototype.fetchAll = function(callback) {
    things.fetchAll(callback);
}

//etc...

module.exports = ThingsProvider;
于 2012-08-23T16:55:25.803 回答
0

嗯,首先我发现 Mongoose 在结构良好的应用程序中比直接 mongo 更容易使用。所以这可能会对你有所帮助。

其次,我认为您尝试做的事情可以通过中间件(应用程序级别或路由级别)轻松完成,因为您已经在使用 express。或者,参数过滤,如果您的查询将根据参数而变化。我在上次看到的模式如下所示:

var User = mongoose.model("user'); // assumes your schema is previously defined

app.param('user_id', function(req,res,next, id){
   User.find(id, function(err,user){
      if(err) next(err);
      else { 
         req.user = user; 
         next();
      }
   });
}); 

它仍然有一些嵌套,但没有你的例子那么糟糕,更易于管理。然后,假设您有一个“/profile”端点,您可以这样做:

app.get('/profile/:user_id', function(req,res){ res.render('profile', req.user); }
于 2012-08-15T19:47:43.613 回答