如何为mongoose查询中返回的每个文档执行异步方法

时间:2014-05-07 13:03:18

标签: javascript node.js mongodb mongoose

我有一个mongoose模型架构设置如下。

var orderSchema = new Schema ({
 _invoices: [{ type: Schema.ObjectId, ref: 'invoice'},
 _discounts: [{ type: Schema.ObjectId, ref: 'discount'},
 _client: String

});

orderSchema.methods.totalInvoiced = function (cb) {
 this.populate('_invoices', function (err, order) {
  cb(err, _.reduce(_.pluck(order._invoices, 'amount'), function (a, b) {
    return a+b;
     }, 0);
     }

};

orderSchema.methods.totalDiscount = function (cb) {
  this.populate('_discounts', function (err, order) {
  cb(err, _.reduce(_.pluck(order.discounts, 'amount'), function (a, b) {
    return a+b;
     }, 0);
     }

};

现在我想获取一系列订单但我希望包含" totalInvoiced"以及" totalDiscount"作为返回集合中每个文档的附加属性。我理解这可能是" totalInvoiced"成为一个虚拟财产,但我并不总是希望它被包括在内。这是我尝试的方式,但我觉得可能有更好的方法来做到这一点。

Order.find({}, function (err, orders) {
     // for each order calc totals and add to document as two new properties
     _.each(orders, function (order) {
       async.parallel({
         invoice: function (cb) {
           order.totalInvoiced(cb);
         },
         discount: function (cb) {
           order.totalDiscount(cb);
         }
       }, function (err, result) {
        order.totalInvoiced = result.invoice;
        order.totalDiscount = result.discount;
       }

     });

     return orders;

    });

我的问题是,对于集合执行查询的最佳方法是什么,还要在每个文档上执行一些异步方法作为查询的一部分,或者我通过迭代结果来执行此操作的方式。查询正确的方法来执行此操作。也许有一个查询流

1 个答案:

答案 0 :(得分:1)

_.each()并非同步,因此在填充所有总计时,您将很难继续执行。此外,如果您无法控制Order.find()将返回多少订单,则可以通过不限制人口限制来解决一些严重的性能问题。

您可以尝试这样的事情:

Order.find({}, function (err, orders) {
    // populate max 15 orders at any time
    async.mapLimit(orders, 15, function (order, cb) {
        async.parallel({
            invoice: function (cb) {
                order.totalInvoiced(cb);
            },
            discount: function (cb) {
                order.totalDiscount(cb);
            }
        }, function (err, result) {
            order.totalInvoiced = result.invoice;
            order.totalDiscount = result.discount;
            return cb(null, order);
        });
    }, function (err, orders) {
        console.log('Done!');
    });
});