多个组的单个聚合查询

时间:2016-11-10 08:22:06

标签: node.js mongodb mongodb-query aggregation-framework

我的收藏JSON

[
   {
      "_id" : 0,  
      "finalAmount":40,
      "payment":[
         {
            "_id":0,
            "cash":20
         },
         {
            "_id":1,
            "card":20
         }
      ]
   },
   {
      "_id" : 1,
      "finalAmount":80,
      "payment":[
         {
            "_id":0,
            "cash":60
         },
         {
            "_id":1,
            "card":20
         }
      ]
   },
   {
      "_id" : 2,
      "finalAmount":80,
      "payment":[
         {
            "_id":0,
            "cash":80
         }
      ]
   }
]

我希望使用聚合框架明智地使用amountcashcard组。有人可以帮忙吗?

请将我的_id视为ObjectId用于演示目的,因为我已经给出0和1.我正在使用Node Js和MongoDB,我希望在一个查询中的预期输出如下:< / p>

预期输出:

{
   "cash":160,
   "card":40,
   "total":200,
   "count":3
}

2 个答案:

答案 0 :(得分:2)

您可以尝试运行以下聚合管道,尽管可能会有一些性能损失或潜在的aggregation pipeline limits包含大量数据集,因为您的初始管道尝试对集合中的所有文档进行分组以获取总文档数和数量以及将所有文档推送到临时列表,这可能会影响管道的性能。

尽管如此,以下解决方案将从给定样本中产生给定的期望输出:

collection.aggregate([
    {
        "$group": {
            "_id": null,
            "count": { "$sum": 1 },
            "doc": { "$push": "$$ROOT" },
            "total": { "$sum": "$finalAmount" }
        }
    },
    { "$unwind": "$doc" },
    { "$unwind": "$doc.payment" },
    {
        "$group": {
            "_id": null,
            "count": { "$first": "$count" },
            "total": { "$first": "$total" },            
            "cash": { "$sum": "$doc.payment.cash" },
            "card": { "$sum": "$doc.payment.card" }
        }
    }
], function(err, result) {
    console.log(result);
});

答案 1 :(得分:0)

在大数据集上运行时,这个问题可能更合适,使用map reduce操作更快解决,因为结果是一个单一的聚合结果。

var map = function map(){
    var cash = 0;
    var card = 0;

    for (i in this.payment){

        if(this.payment[i].hasOwnProperty('cash')){
            cash += this.payment[i]['cash']
        }
        if(this.payment[i].hasOwnProperty('card')){
            card += this.payment[i]['card']
        }
    }

    var doc = {
        'cash': cash,
        'card': card,
    };
    emit(null, doc);    
};

var reduce = function(key, values){

    var total_cash = 0;
    var total_card = 0;
    var total = 0;

    for (i in values){
        total_cash += values[i]['cash']
        total_card += values[i]['card']
    }

    var result = {
        'cash': total_cash,
        'card': total_card,
        'total': total_cash+ total_card,
        'count': values.length
    };

    return result
};


db.runCommand({"mapReduce":"test", map:map, reduce:reduce, out:{replace:"test2"}})

结果:

db.test2.find().pretty()
    {
        "_id" : null,
        "value" : {
            "cash" : 160,
            "card" : 40,
            "total" : 200,
            "count" : 3
        }
    }