如何从内部数组中找到总值的总和?

时间:2016-04-01 05:17:21

标签: mongodb mongodb-query aggregation-framework

{ 
    "_id" : ObjectId("56fb04fd2e6bb8bc059287c9"), 
    "BillNo" : "Bill_001", 
    "DateP" : "12-12-2015", 
    "Type" : "Cash", 
    "Items" : [
        {
            "id" : NumberInt(1), 
            "ItemName" : "cement", 
            "Qty" : "100", 
            "Rate" : "10", 
            "Total" : "1000"
        }, 
        {
            "id" : NumberInt(2), 
            "ItemName" : "steel", 
            "Qty" : "10", 
            "Rate" : "50", 
            "Total" : "500"
        }, 
        {
            "id" : NumberInt(3), 
            "ItemName" : "sand", 
            "Qty" : "1", 
            "Rate" : "1500", 
            "Total" : "1500"
        }
    ]
}
{ 
    "_id" : ObjectId("56fb05382e6bb8bc059287ca"), 
    "BillNo" : "Bill_002", 
    "DateP" : "12-10-2015", 
    "Type" : "Cash", 
    "Items" : [
        {
            "id" : NumberInt(1), 
            "ItemName" : "Paint", 
            "Qty" : "50", 
            "Rate" : "100", 
            "Total" : "5000"
        }, 
        {
            "id" : NumberInt(2), 
            "ItemName" : "Brush", 
            "Qty" : "5", 
            "Rate" : "10", 
            "Total" : "50"
        }
    ]
}

在上面的集合中,将主文档中的所有购买详细信息及其项目详细信息存储为主项目的内部数组。我需要使用mongodb获得如下结果;如何在mongodb中从内部数组中找到总数。

Bill_001     1500
Bill_002     5050

1 个答案:

答案 0 :(得分:2)

理想情况下,在MongoDB中,您可以将$map$sum同时用作$group累加器,以及添加所提供数组成员的新角色:

db.collection.aggregate({
   { "$group": {
       "_id": "$BillNo",
       "Total": {
           "$sum": {
               "$sum": {
                  "$map": {
                     "input": "$Items",
                     "as": "item",
                     "in": "$$item.Total"
                  }
               }
           }
       }
   }}
})

或仅根据文件:

db.collection.aggregate({
   { "$group": {
       "_id": "$_id",
       "BillNo": { "$first": "$BillNo" },
       "DateP": { "$first" "$DateP" },
       "Type": { "$first": "$Type" }
       "Total": {
           "$sum": {
               "$sum": {
                  "$map": {
                     "input": "$Items",
                     "as": "item",
                     "in": "$$item.Total"
                  }
               }
           }
       }
   }}
})

使用$first的其他累加器。当然,你可以使用MongoDB 3.2来实现$project

db.collection.aggregate({
   { "$project": {
       "BillNo": 1,
       "DateP": 1,
       "Type": 1,
       "Total": {
           "$sum": {
              "$map": {
                 "input": "$Items",
                 "as": "item",
                 "in": "$$item.Total"
              }
           }
       }
   }}
})

在旧版本中,您首先需要$unwind数组:

db.collection.aggregate([
    { "$unwind": "$Items" },
    { "$group": {
       "_id": "$BillNo",
       "Total": {
           "$sum": "$Items.Total"
       }
    }}
])

或者,如果您只是按文档添加:

db.collection.aggregate([
    { "$unwind": "$Items" },
    { "$group": {
       "_id": "_id",
       "BillNo": { "$first": "$BillNo" },
       "DateP": { "$first": "$DateP" },
       "Type": { "$first": "$Type" },
       "Total": {
           "$sum": "$Items.Total"
       }
    }}
])

但是当然只有在你将字符串固定为数值时才会这样。

理想情况下,您可以像这样修复它:

var ops = [];

db.collection.find().forEach(function(doc) {
    doc.Items.forEach(function(item) {
        ops.push({
            "updateOne": {
                "filter": { "_id": doc._id, "Items.id": item.id },
                "update": {
                    "$set": {
                        "Items.$.Qty": parseInt(item.Qty),
                        "Items.$.Rate": parseInt(item.Rate),
                        "Items.$Total": parseInt(item.Total)
                    }
                }
            }        
        });

        // Send batch of updates
        if ( ops.length == 1000 ) {
            db.collection.bulkWrite(ops);
            ops = [];
        }
    })
});

// Clear any unprocessed updates
if ( ops.length > 0 ) {
    db.collection.bulkWrite(ops);
}