Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDb $addFields inside arrays that $multiply two values within the array

MongoDb version 3.4.4

How to aggregate a new key 'total', whose value is the product of 'course' and 'quantity' for each object inside array snapshot.

Sample document:

{
    cur: "EUR",
    snapshot: [
        {
            id: "24352345",
            course: 58.12,
            quantity: 13
        },    
        {
            id: "34552345",
            course: 18.12,
            quantity: 63
        }
    ]
}

Desired result:

{
    cur: "EUR",
    snapshot: [
        {
            id: "24352345",
            course: 58.12,
            quantity: 13,
            total: 755.56
        },    
        {
            id: "34552345",
            course: 18.12,
            quantity: 63,
            total: 1141.56
        }
    ]
}

first attempt:

db.mycoll.aggregate([{
    $addFields: {
        "snapshot.total": {
            $multiply:["$snapshot.quantity", "$snapshot.course"]
        }
    }
}])

"errmsg" : "$multiply only supports numeric types, not array"

Second attempt:

db.mycoll.aggregate( [ 
    { "$addFields": { 
        "snapshot.total": {
            "$map": { 
                "input": "$snapshot", 
                "as": "row", 
                "in": { "$multiply": [ 
                    { "$ifNull": [ "$$row.quantity", 0 ] }, 
                    { "$ifNull": [ "$$row.course", 0 ] } 
                ]} 
            }
        } 
    }} 
])

The undesired value of 'total' is an array with the totals of all the objects:

{
    cur: "EUR",
    snapshot: [
        {
            id: "24352345",
            course: 58.12,
            quantity: 13,
            total: [
                755.56,
                1141.56
            ]
        },    
        {
            id: "34552345",
            course: 18.12,
            quantity: 63,
            total: [
                755.56,
                1141.56
            ]
        }
    ]
}
like image 608
tonphai Avatar asked May 13 '17 10:05

tonphai


1 Answers

Modify your second attempt using the $map operator to map the whole snapshot embedded document with its fields as

db.mycoll.aggregate([
    {
        "$addFields": {
            "snapshot": {
                "$map": {
                    "input": "$snapshot",
                    "as": "row",
                    "in": {
                        "id": "$$row.id",
                        "course": "$$row.course",
                        "quantity": "$$row.quantity",
                        "total": { "$multiply": [ 
                            { "$ifNull": [ "$$row.quantity", 0 ] }, 
                            { "$ifNull": [ "$$row.course", 0 ] } 
                        ]} 
                    }
                }
            }
        }
    }
])
like image 153
chridam Avatar answered Nov 15 '22 12:11

chridam