Md Nazmul Hossain
Md Nazmul Hossain

Reputation: 2923

Need to sum from array object value in mongodb

I am trying to calculate total value if that value exits. But query is not working 100%. So can somebody help me to solve this problem. Here my sample document. I have attached two documents. Please these documents & find out best solution Document : 1

{
    "_id" : 1"),
    "message_count" : 4,
    "messages" : {
        "data" : [ 
            {
                "id" : "11",
                "saleValue": 1000
            }, 
            {
                "id" : "112",
                "saleValue": 1400
            }, 
            {
                "id" : "22",

            }, 
            {
                "id" : "234",
                "saleValue": 111
            }
        ],

    },
    "createdTime" : ISODate("2018-03-18T10:18:48.000Z")
}

Document : 2

 {
        "_id" : 444,
        "message_count" : 4,
        "messages" : {
            "data" : [ 
                {
                    "id" : "444",
                    "saleValue" : 2060
                }, 
                {
                    "id" : "444",
                }, 
                {
                    "id" : 234,
                    "saleValue" : 260
                }, 
                {
                    "id" : "34534",
                }
            ]
        },

        "createdTime" : ISODate("2018-03-18T03:11:50.000Z")
    }

Needed Output:

{
   total : 4831
}

My query :

db.getCollection('myCollection').aggregate([
    {
        "$group": {
            "_id": "$Id",

            "totalValue": {
                $sum: {
                    $sum: "$messages.data.saleValue"
                }
            }

        }
    }
])

So please if possible help me to solve this problem. Thanks in advance

Upvotes: 5

Views: 18221

Answers (5)

Sudip Bhujel
Sudip Bhujel

Reputation: 36

You can do it without using $group. Grouping makes other data to be managed and addressed. So, I prefer using $sum and $map as shown below:

db.getCollection('myCollection').aggregate([
 {
   $addFields: {
      total: {
          $sum: {
            $map: {
              input: "$messages.data",
              as: "message",
              in: "$$message.saleValue",
            },
          },
        },
      },
    }, 
  } 
])

Upvotes: 1

chridam
chridam

Reputation: 103345

It's not working correctly because it is aggregating all the documents in the collection; you are grouping on a constant "_id": "tempId", you just need to reference the correct key by adding the $ as:

db.getCollection('myCollection').aggregate([
    { "$group": {
        "_id": "$tempId",
        "totalValue": { 
            "$sum": { "$sum": "$messages.data.saleValue" } 
        }
    } }
])

which in essence is a single stage pipeline version of an aggregate operation with an extra field that holds the sum expression before the group pipeline then calling that field as the $sum operator in the group.

The above works since $sum from MongoDB 3.2+ is available in both the $project and $group stages and when used in the $project stage, $sum returns the sum of the list of expressions. The expression "$messages.data.value" returns a list of numbers [120, 1200] which are then used as the $sum expression:

db.getCollection('myCollection').aggregate([
    { "$project": {
        "values": { "$sum": "$messages.data.value" },
        "tempId": 1,
    } },
    { "$group": {
        "_id": "$tempId",
        "totalValue": { "$sum": "$values" }
    } }
])

Upvotes: 8

Rubin Porwal
Rubin Porwal

Reputation: 3845

According to description as mentioned into above question, as a solution please try executing following aggregate query

db.myCollection.aggregate(

    // Pipeline
    [
        // Stage 1
        {
            $unwind: {
                path: '$messages.data'
            }
        },

        // Stage 2
        {
            $group: {
                _id: {
                    pageId: '$pageId'
                },
                total: {
                    $sum: '$messages.data.saleValue'
                }
            }
        },

        // Stage 3
        {
            $project: {
                pageId: '$_id.pageId',
                total: 1,
                _id: 0
            }
        }

    ]


);

Upvotes: 1

Clement Amarnath
Clement Amarnath

Reputation: 5466

db.getCollection('myCollection').aggregate([
   {
     $unwind: "$messages.data",
     $group: {
        "_id": "tempId",
        "totalValue": { $sum: "$messages.data.value" }
     }
   }
])

$unwind

Upvotes: 1

Alejandro Montilla
Alejandro Montilla

Reputation: 2654

You can add a $unwind before your $group, in that way you will deconstructs the data array, and then you can group properly:

db.myCollection.aggregate([
{
    "$unwind": "$messages.data"
},
{
    "$group": {
        "_id": "tempId",
        "totalValue": {
            $sum: {
                $sum: "$messages.data.value"
            }
        }
    }
}
])

Output:

{ "_id" : "tempId", "totalValue" : 1320 }

Upvotes: 1

Related Questions