5

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

1
  • 1
    Use unwind on the data array and then sum the data.value Commented Mar 26, 2018 at 12:23

5 Answers 5

8

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" }
    } }
])
Sign up to request clarification or add additional context in comments.

9 Comments

you query worked fine for my demo document. But not worked for my actual one. If I will share my actual data with you, can you check please ??
I have updated my question. Please check this & help me to figure out.
It's failing because "saleValue" is a string, not a number. $sum doesn't work properly with string values, try to convert the fields to numerical values before running the pipeline.
Need just pageId as _id & total.
But query is not working 100% Please show what you are getting as a result and the query you are using. Are you still using "_id": "pageId", in your $group pipeline step? If so, you need to change that to point to the correct key, like "_id": "$pageId", as explained in the above answer if you were following. Also check if your MongoDB server version >= 3.2.
|
1

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 }

Comments

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

$unwind

Comments

1

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
            }
        }

    ]


);

Comments

1

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",
            },
          },
        },
      },
    }, 
  } 
])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.