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:hello#lhd.net"
},
"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
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"
},
}
}])
Related
I have the following structure:
{
"data": {
"array_1": [
{
"name": "Robert Kalani"
},
{
"name": "Balkan Boy",
}
],
"array_2": [
{
"name": "Pepe Dolan"
},
{
"name": "John Nolan",
}
],
"array_3": [
{
"name": "Phillip A. Luna",
},
{
"name": "Eugene Garcia"
}
]
}
}
I would like to sort each array by the name key in alpabetical order, not sure on how to do that, I've read about array_multisort but it seemed not to work. Would greatly appreciate some help
Here is the expected output
{
"data": {
"array_1": [
{
"name": "Balkan Boy",
},
{
"name": "Robert Kalani"
}
],
"array_2": [
{
"name": "John Nolan"
},
{
"name": "Pepe Dolan"
}
],
"array_3": [
{
"name": "Eugene Garcia"
},
{
"name": "Phillip A. Luna"
}
]
}
}
// Your JSON Data
$data = '{
"data": {
"array_1": [{ "name": "Robert Kalani" }, { "name": "Balkan Boy" }],
"array_2": [{ "name": "Pepe Dolan" }, { "name": "John Nolan" }],
"array_3": [{ "name": "Phillip A. Luna" }, { "name": "Eugene Garcia" }]
}
}
';
$result = [];
// Convert your JSON data to associative array
$array = json_decode($data, true)['data'];
function sort_by_name($a, $b)
{
return $a > $b;
}
foreach ($array as $item) {
uasort($item, "sort_by_name");
$result[] = $item;
}
echo "<pre>";
print_r($result);
Result:
Array
(
[0] => Array
(
[1] => Array
(
[name] => Balkan Boy
)
[0] => Array
(
[name] => Robert Kalani
)
)
[1] => Array
(
[1] => Array
(
[name] => John Nolan
)
[0] => Array
(
[name] => Pepe Dolan
)
)
[2] => Array
(
[1] => Array
(
[name] => Eugene Garcia
)
[0] => Array
(
[name] => Phillip A. Luna
)
)
)
I have this output results from database:
Array
(
[0] => stdClass Object
(
[name] => attr one
[attribute_id] => 1
[attribute_group] => group one
[attribute_group_id] => 1
)
[1] => stdClass Object
(
[name] => attr two
[attribute_id] => 2
[attribute_group] => group one
[attribute_group_id] => 1
)
[2] => stdClass Object
(
[name] => attr three
[attribute_id] => 3
[attribute_group] => group one
[attribute_group_id] => 1
)
[3] => stdClass Object
(
[name] => attr four
[attribute_id] => 4
[attribute_group] => group two
[attribute_group_id] => 2
)
)
now for json ouput:
foreach ($results as $result) {
$json[] = array(
'id' => $result->attribute_group_id,
'text' => $result->attribute_group,
'children' => [array(
'id' => $result->attribute_id,
'text' => $result->name,
)]
);
}
return json_encode($json);
output is:
[
{
"id":"1",
"text":"group one",
"children":[
{
"id":"1",
"text":"attr one"
}
]
},
{
"id":"1",
"text":"group one",
"children":[
{
"id":"2",
"text":"attr two"
}
]
},
{
"id":"1",
"text":"group one",
"children":[
{
"id":"3",
"text":"attr three"
}
]
},
{
"id":"2",
"text":"group two",
"children":[
{
"id":"4",
"text":"attr four"
}
]
}
]
But In Action I need to output grouped by attribute_group and listed in children like this:
[
{
"id":"1",
"text":"group one",
"children":[
{
"id":"1",
"text":"attr one"
},
"id":"2",
"text":"attr two"
},
{
"id":"3",
"text":"attr three"
}
]
},
{
"id":"2",
"text":"group two",
"children":[
{
"id":"4",
"text":"attr four"
}
]
}
]
how do can i create this json output?!
Instead of creating an array $json with an element for each attribute, you should gather each attribute directly by attribute_group_id.
In order to do that, the idea is to use the attribute_group_id as the key of your $json array ($json[$result->attribute_group_id]). If an entry already exists for $json[$result->attribute_group_id]['children'] then you just have to had the current children to this item. If not, you create the entry for the current attribute group ID with his information (id,text,children).
Finally you can return the $json without the key that we used for grouping the attributes using array_values (returns the values of an array without keys).
foreach ($results as $result) {
if(isset($json[$result->attribute_group_id]['children'])){
$json[$result->attribute_group_id]['children'][] = array(
'id' => $result->attribute_id,
'text' => $result->name,
);
}
else {
$json[$result->attribute_group_id] = array(
'id' => $result->attribute_group_id,
'text' => $result->attribute_group,
'children' => [array(
'id' => $result->attribute_id,
'text' => $result->name,
)]
);
}
}
return json_encode(array_values($json));
Result :
[
{
"id": "1",
"text": "group one",
"children": [
{
"id": "1",
"text": "attr one"
},
{
"id": "2",
"text": "attr two"
},
{
"id": "3",
"text": "attr three"
}
]
},
{
"id": "2",
"text": "group two",
"children": [
{
"id": "4",
"text": "attr four"
}
]
}
]
I need to get an JSON structure as following:
{
"emails": [
{
"sender": "shihas#abc.com",
"unread_count": 2,
"items": [
{
"id": "89",
"email": "shihas#abc.com",
"read": "0",
},
{
"id": "32",
"email": "shihas#abc.com",
"read": "0",
}
]
},
{
"sender": "marias123#gmail.com",
"unread_count": 0,
"items": [
{
"id": "2",
"email": "marias123#gmail.com",
"read": "1",
}
]
},
{
"sender": "gutar4320#hotmail.com",
"unread_count": 1,
"items": [
{
"id": "1",
"email": "gutar4320#hotmail.com",
"read": "0",
}
]
}
]
}
Array($hire_email):
In the below array I need to group all the details based on the email. And also count the no. of unread messages(i.e read = 0).
Array
(
[0] => Array
(
[id] => 89
[email] => shihas#abc.com
[read] => 0
)
[1] => Array
(
[id] => 32
[email] => shihas#abc.com
[read] => 0
)
[2] => Array
(
[id] => 2
[email] => marias123#gmail.com
[read] => 1
)
[3] => Array
(
[id] => 1
[email] => gutar4320#hotmail.com
[read] => 0
)
)
The following is the code snippet used for maintaining the JSON structure.
foreach($hire_email as $val) {
if($val['read']==0){ $count++; }else{ $count = 0;}
$hire_group_email[$val['email']]['sender'] = $val['email'];
$hire_group_email[$val['email']]['unread_count'] = $count;
$hire_group_email[$val['email']]['items'][] = $val;
}
$output["emails"][] = $hire_group_email;
echo json_encode($output);
This should do the trick.
$hire_email =array(
array(
"id" => "89",
"email" => "shihas#abc.com",
"read" => "0"
),
array
(
"id" => "32",
"email" => "shihas#abc.com",
"read" => "0"
),
array
(
"id" => "2",
"email" => "marias123#gmail.com",
"read" => "1"
),
array
(
"id" => "1",
"email" => "gutar4320#hotmail.com",
"read" => "0"
)
);
$tmp = array();
foreach($hire_email as $arg)
{
$tmp[$arg['email']][] = $arg;
}
$output = array();
foreach($tmp as $type => $labels)
{
$count = 0;
foreach ($labels as $value) {
if($value['read']==0){ $count++; }else{ $count = 0;}
}
$output[] = array(
'sender' => $type,
'unread_count' => $count,
'items' => $labels
);
}
echo json_encode($output);
Try doing it like this, using: array_sum and array_column, the rest is just picking out the first items values.
$array = json_decode($json, true)['emails'];
$result = [];
foreach($array as $val) {
$result[] = [
'id' => $val['items'][0]['id'],
'email' => $val['items'][0]['email'],
'read' => array_sum(array_column($val['items'], 'read'))
];
}
$output["emails"] = $result;
echo json_encode($output, JSON_PRETTY_PRINT);
Result:
{
"emails": [
{
"id": "89",
"email": "shihas#abc.com",
"read": 0
},
{
"id": "2",
"email": "marias123#gmail.com",
"read": 1
},
{
"id": "1",
"email": "gutar4320#hotmail.com",
"read": 0
}
]
}
https://3v4l.org/hi7qm
And if you want it as shown ;p (my mistake, misread it):
Loop over each item, then loop over the items and use that to build the output.
$array = json_decode($json, true)['emails'];
$result = [];
foreach($array as $val) {
foreach ($val['items'] as $item) {
$result[] = [
'id' => $item['id'],
'email' => $item['email'],
'read' => array_sum(array_column($val['items'], 'read'))
];
}
}
$output["emails"] = $result;
echo json_encode($output, JSON_PRETTY_PRINT);
Result:
{
"emails": [
{
"id": "89",
"email": "shihas#abc.com",
"read": 0
},
{
"id": "32",
"email": "shihas#abc.com",
"read": 0
},
{
"id": "2",
"email": "marias123#gmail.com",
"read": 1
},
{
"id": "1",
"email": "gutar4320#hotmail.com",
"read": 0
}
]
}
https://3v4l.org/eU95A
I'm a newb when it comes to PHP and API's so please forgive me if I make any mistakes in terminology etc.
I'm creating an API to call Data from ADFORM reports, and have issues in selecting various metrics.
I make a POST to https://api.adform.com/v1/reportingstats/agency/reportdata
{
"dimensions": [
"client",
"campaign"
],
"metrics": [
"clicks",
"impressions"
],
"filter": {
"date": "campaignStartToEnd"
}
}
The response:
Array
(
[reportData] => Array
(
[columnHeaders] => Array
(
[0] => client
[1] => campaign
[2] => clicks
[3] => impressions
)
[columns] => Array
(
[0] => Array
(
[key] => client
)
[1] => Array
(
[key] => campaign
)
[2] => Array
(
[key] => clicks
[specs] => Array
(
[dataSource] => adform
[adUniqueness] => all
)
)
[3] => Array
(
[key] => impressions
[specs] => Array
(
[dataSource] => adform
[adUniqueness] => all
)
)
)
In the response the adUniqueness = "all" which is a default however from the Adform documentation (http://api.adform.com/help/references/buyer-solutionsc/reporting/metadata/metrics) there are other statistics for uniqueness level.
{
"metricsMetadata": [
{
"key": "clicks",
"category": "Delivery",
"displayName": "Clicks",
"displayFormat": "n0",
"description": "This metric shows the number of clicks for the selected dimension. A click occurs when a user interacts with the advertisement by engaging a mouse button (usually the left) while the mouse pointer is hovering over the advertisement.",
"specsMetadata": [
{
"key": "adUniqueness",
"displayName": "Uniqueness",
"description": "Display statistics for selected uniqueness level",
"specValuesMetadata": [
{
"key": "all",
"displayName": "All",
"isDefault": true,
"description": ""
},
{
"key": "campaignUnique",
"displayName": "Campaign unique",
"isDefault": false,
"description": ""
}
]
}
]
}
How do I add the "campaignUnique" to the POST?
{
"dimensions": [
"client",
"campaign"
],
"metrics": [
{
"metric": "impressions",
"specs": {
"adUniqueness": "campaignUnique"
}
},
{
"metric": "impressions",
"specs": {
"adUniqueness": "all"
}
},
{
"metric": "clicks",
"specs": {
"adUniqueness": "campaignUnique"
}
},
{
"metric": "clicks",
"specs": {
"adUniqueness": "all"
}
}
],
"filter": {
"date": {"from":"2018-01-01", "to":"2018-02-20"}
}
}
It works like I need:
$out = $collection->aggregate(
array(
'$match' => array('type' => 'chair')
),
array(
'$project' => array(
'chairtype' => 1,
'mijczjeqeo'=>1
)
),
array(
'$group' => array(
'_id' => '$chairtype',
'MIDDLE_mijczjeqeo' => array('$avg' => '$mijczjeqeo'),
'SUMMA__mijczjeqeo' => array('$sum' => '$mijczjeqeo')
)
)
);
my_dump($out);
But i need to get true data for aggregation from array in the same documents: versions[0][content][mijczjeqeo]
Please correct my script. It does not work:
$out = $collection->aggregate(
array(
'$match' => array('type' => 'chair')
),
array(
'$project' => array(
'chairtype' => 1,
'versions.0.content.mijczjeqeo'=>1
)
),
array(
'$group' => array(
'_id' => '$chairtype',
'MIDDLEmijczjeqeo' => array('$avg' => '$versions.0.content.mijczjeqeo'),
'SUMMAmijczjeqeo' => array('$sum' => '$versions[0]["content"]["mijczjeqeo"]')
)
)
);
no one method does not work:
'MIDDLEmijczjeqeo' => array('$avg' => '$versions.0.content.mijczjeqeo')
'SUMMAmijczjeqeo' => array('$sum' => '$versions[0]["content"]["mijczjeqeo"]')
I think the problem near .0.
I try to do it in mongo console...
db.documents.aggregate({$match:{'type':'chair'}},{$project:{'chairtype': 1, 'mijczjeqeo':1}},{$group:{'_id':'$chairtype','MID':{$avg:'$mijczjeqeo'}}})
{
"result" : [
{
"_id" : "T",
"MID" : 6.615384615384615
},
{
"_id" : "G",
"MID" : 8.310344827586206
},
{
"_id" : "E",
"MID" : 6.9523809523809526
}
],
"ok" : 1
}
db.documents.aggregate({$match:{'type':'chair'}},{$project:{'chairtype': 1, 'versions.0.content.mijczjeqeo':1}},{$group:{'_id':'$chairtype','MID':{$avg:'$versions.0.content.mijczjeqeo'}}})
{
"result" : [
{
"_id" : "T",
"MID" : 0
},
{
"_id" : "G",
"MID" : 0
},
{
"_id" : "E",
"MID" : 0
}
],
"ok" : 1
}
Well you cannot project like that in the aggregation pipeline. If you want to act on array elements within an aggregation statement you first need to $unwind the array and then either $match the required element(s) or as in your case choose the $first item using an additional $group stage.
Your question does not show the structure of a document so I'll just use a sample, as my "chairs" collection:
{
"_id": 1,
"type": "chair",
"chairtype": "A",
"versions": [
{
"revision": 1,
"content": {
"name": "ABC",
"value": 10
}
},
{
"revision": 2,
"content": {
"name": "BBB",
"value": 15
}
}
]
}
{
"_id": 2,
"type": "chair",
"chairtype": "A",
"versions": [
{
"revision": 1,
"content": {
"name": "CCC",
"value": 20
}
},
{
"revision": 2,
"content": {
"name": "BAB",
"value": 12
}
}
]
}
Minimal, but enough to get the point. Now the aggregate statement:
db.chairs.aggregate([
// Normal query matching, which is good
{ "$match": { "type": "chair" } },
// Unwind the array to de-normalize
{ "$unwind": "$versions" },
// Group by the document in order to get the "first" array element
{ "$group": {
"_id": "$_id",
"chairtype": { "$first": "$chairtype" },
"versions": { "$first": "$versions" }
}},
// Then group by "chairtype" to get your average values
{ "$group": {
"_id": "$chairtype",
"MID": {"$avg": "$versions.content.value"}
}}
])
Of course if your actual document has nested arrays then you will be "unwinding" and "matching" the required elements. But that is the general process of "narrowing down" the array contents to the elements you need.