Tanmay Sakhale
Tanmay Sakhale

Reputation: 63

How do we sum individual array elements in MongoDB aggregation query?

Document :
  {
    "version": "1.0.0",
    "actor": {
        "objectType": "Agent",
        "name": "Test user",
        "account": {
            "homePage": "http://testing.com/",
            "name": "67"
        }
    },
    "verb": {
        "id": "http://adlnet.gov/expapi/verbs/completed",
        "display": {
            "en-US": "completed"
        }
    },
    "object": {
        "objectType": "Activity",
        "id": "http://localhost/action?id=cji",
        "definition": {
            "type": "http://adlnet.gov/expapi/activities/lesson",
            "name": {
                "en-US": "ps3"
            },
            "description": {
                "en-US": "ps3"
            }
        }
    },
    "timestamp": "2016-10-25T11:21:25.917Z",
    "context": {
        "extensions": {
            "http://localhost/eventinfo": {
                "sessionId": "1477393533327",
                "starttm": "1477394351210",
                "eventtm": "1477394485917",
                "course": "cji"
            }
        },
        "contextActivities": {
            "parent": [
                {
                    "objectType": "Activity",
                    "id": "http://localhost/id=cji"
                }
            ]
        }
    },
    "result": {
        "duration": "PT2M14.71S",
        "score": {
            "raw": 6,
            "max": 21
        }
    },
    "authority": {
        "objectType": "Agent",
        "name": "New Client",
        "mbox": "mailto:[email protected]"
    },
    "stored": "2016-10-25T11:20:29.666700+00:00",
    "id": "c7039783-371f-4f59-a665-65a9d09a2b7f"
}

We've got this PHP + MongoDB aggregation query:

    $condition = array(
                 array(
                '$match' => array(
                    'client_id' => $CFG->mongo_clientid,
                    'statement.actor.account.name' => array('$in'=> array('67','192','213')),
                    'statement.verb.id' => 'http://adlnet.gov/expapi/verbs/completed',
                    'statement.object.id' => 'http://localhost/action?id=cji'
                )),
                 array(
                '$group' => array(
                    '_id' =>  '$statement.actor.account.name' ,
                    //'totalpoints' =>array( '$sum' => array('$last' => '$statement.result.score.raw'))                
                    'laststatement' => array('$last' => '$statement.result.score.raw'),
                    //'sumtest' => array('$add' => ['$laststatement'])
                     )
                  )
            );
             $cursor = $collection->aggregate($condition);
             echo "
";
             print_r($cursor);
             echo "
"; which returns this result: Array ( [result] => Array ( [0] => Array ( [_id] => 192 [laststatement] => MongoInt64 Object ( [value] => 4 ) ) [1] => Array ( [_id] => 67 [laststatement] => MongoInt64 Object ( [value] => 6 ) ) ) [ok] => 1 )

How do we sum [laststatement].[value] of these individual array elements in MongoDB aggregation query?

[laststatement] => MongoInt64 Object
                        (
                            [value] => values goes here
                        )

Also, how do we use $last and $sum together in MongoDB aggregation query? In my result there are 2 raw scores(last statement) for 2 different id (192,67). I want to sum this scores like 4 + 6 = 10 for all multiple id's but want only the last scores from the last statement. I am unable to use $last and $sum on the line. Please check

Upvotes: 2

Views: 982

Answers (1)

s7vr
s7vr

Reputation: 75934

Looks like all you want is a single group. So the grouping id should be null. You may want to add a sort if you care for what last record should be. Not tested.

array(
      '$group' => array(
      '_id' =>  null ,
      'totalpoints' => array( '$sum' => '$statement.result.score.raw')                
      'laststatement' => array('$last' => '$statement.result.score.raw')
     )
)

Here is the mongo shell version.

aggregate([
    {
       $match :{
             "actor.account.name":{$in:["67","192","213"]},
             "verb.id":{$eq:"http://adlnet.gov/expapi/verbs/completed"},
             "object.id":{$eq:"http://localhost/action?id=cji"}
       }
    },
    {
      $group: {
          "_id": null,
          "totalpoints" : {$sum:"$result.score.raw"},                
          "laststatement" :{$last:"$result.score.raw"}
      }
    }
])

Output:

{ "_id" : null, "totalpoints" : 10, "laststatement" : 4 }

Update Changed to include the sum for the last statement from each group. The first grouping is by actor name and returns the last statement from each group. The second grouping sums all the last statement.

aggregate([{
    $match: {
        "actor.account.name": {
            $in: ["67", "192", "213"]
        },
        "verb.id": {
            $eq: "http://adlnet.gov/expapi/verbs/completed"
        },
        "object.id": {
            $eq: "http://localhost/action?id=cji"
        }
    }
}, {
    $group: {
        "_id": "$actor.account.name",
        "laststatement": {
            $last: "$result.score.raw"
        }
    }
}, {
    $group: {
        "_id": null,
        "totalpoints": {
            $sum: "$laststatement"
        },
    }
}])

Upvotes: 2

Related Questions