mongodb - php - aggregate projection and match - php

I'm trying to match criteria (cl=1) and then aggregate all the results by month (I've tried year/month/date as well to no luck).
When I run the code below it seems like it works properly, the output shows the months etc, however none of the stats are being added.
The $du field in Mongo is a MongoDate object.
Does anyone have any idea what I'm doing wrong?
See very bottom for a code snippet that is searched by date and returns a result.
$result = $collection->aggregate(
array(
array('$match' => array(
'cl' => $app_id) # application id, int such as "2"
),
array('$project' => array(
//'year' => array('$year' => '$du'),
'month' => array('$month' => '$du'),
//'week' => array('$week' => '$du'),
)),
array('$group' =>
array(
'_id' => array(
'month' => '$month',
),
'i' => array('$sum' => '$vs.i'),
'r' => array('$sum' => '$vs.r'),
'u' => array('$sum' => '$vs.u'),
)
),
array(
'$sort' => array(
'_id' => -1
)
),
array(
'$limit' => 14
)
)
);
Output:
Array
(
[result] => Array
(
[0] => Array
(
[_id] => Array
(
[month] => 10
)
[i] => 0
[r] => 0
[u] => 0
)
[1] => Array
(
[_id] => Array
(
[month] => 9
)
[i] => 0
[r] => 0
[u] => 0
)
.......
working - searching by date
$start = new MongoDate(strtotime("2012-10-01 00:00:00"));
$end = new MongoDate(strtotime("2013-10-15 00:00:00"));
$cursor = $collection->find(array("du" => array('$gt' => $start, '$lte' => $end)));
while ($cursor->hasNext()) {
$document = $cursor->getNext();
print_r($document);exit;
}
# RESPONSE
Array
(
[_id] => MongoId Object
(
[$id] => 51acbfd33dd49497848a8e5b
)
[cl] => 1
[du] => MongoDate Object
(
[sec] => 1370275795
[usec] => 0
)
[vs] => Array
(
[i] => 11
[u] => 1
)
)

The stats aren't there because you haven't chosen to project them. Project gives you _id by default, but anything else you want must be specified.
You'll need something like this instead of your current $project:
array('$project' => array(
'month' => array('$month' => '$du'),
'vs' => 1
))

Related

Php check and replace if value exist in multi array?

Problem:
I dont know/understand how to check if date and place exists on the same "row" and they exists more then once.
Second, how do i then merge an array
my case MergeArray with ArraySchedule
Code:
$ArraySchedule = array();
while ($data = $stmt -> fetch(PDO::FETCH_ASSOC)) {
$schedules = array(
"id" => $data['id'],
"name" => $data['name'],
"date" => $data['date'],
"time" => $data['time'],
"place_id" => $data['place_id'],
"place" => $data['place'],
);
array_push($ArraySchedule, $schedules);
}
$dupe_array = array();
foreach ($ArraySchedule as $key => $value) {
if(++$dupe_array[$value["date"]] > 1 && ++$dupe_array[$value["place_id"]] > 1 ){
// this statement is wrong, i want something like:
// if date and place_id exists on the same "row" and they exists more then once
}
}
What i want to do:
Check if ArraySchedule contains schedules that have the same date and place,
if there is more than one schedule that has the same date and place_id.
then I want to update ArraySchedule with this structure
$MergeArray = array(
"id" => ArraySchedule['id'],
"name" => array(
"name" => scheduleSameDateAndPlace['name'],
"name" => scheduleSameDateAndPlace['name'],
"name" => scheduleSameDateAndPlace['name'],
),
"date" => $ArraySchedule['date'],
"time" => $ArraySchedule['time'],
"place_id" => $ArraySchedule['place_id'],
"place_name" => $ArraySchedule['place_name'],
),
MergeArray with ArraySchedule?
anyway...
Output I think I want?
Print_r($ArraySchedule)
array(
[0] =>
array(
[id] => 1
[names] => Simon
[date] => 2019-01-02
[time] 18.00
[place_id] => Tystberga Park
[place] => Tystberga
)
[1] =>
array(
[id] => 2
//[names] insted of [name]?
[names] =>
array(
[name] => Vincent
[name] => Angel
[name] => Kim
)
[date] => 2019-02-17
[time] => 13.00
[place_id] => Borås Park
[place] => Borås
)
[2] =>
array(
[id] => 3
// [names] is always an array?
[names] => Caitlyn
[date] => 2019-03-15
[time] 13.00
[place_id] => Plaza Park
[place] => EvPark
)
)
You can use array-reduce. Consider the following:
function mergeByDateAndPlace($carry, $item) {
$key = $item["place_id"] . $item["date"]; // creating key matching exact place and date
if (!isset($carry[$key])) {
$carry[$key]["name"] = $item["name"];
} else {
$carry[$key] = $item;
$item["name"] = [$item["name"]]; // make default array with 1 element so later can be append other names
}
return $carry;
}
Now use it with:
$MergeArray = array_reduce($ArraySchedule, "mergeByDateAndPlace", []);
If you later want to know if there were any duplicate you can just loop on $MergeArray. You can also use array_values if you want to discard the concat keys.
Notice #Nick 2 important comment about saving the first loop and the "time" value that need to be decided. Also notice your desire output contain multi element with the same key ("name") - you need to append them with int key - Array can not have duplicate keys.
Hope that helps!
Here is my data from my database:
var_export($ArraySchedule)
array (
0 => array ( 'id' => '225', 'place_id' => 'Alviks Kulturhus', 'name' => 'BarraBazz', 'date' => '2019-03-19', 'placeadress' => 'Gustavslundsvägen 1', ),
1 => array ( 'id' => '229', 'place_id' => 'Axelhuset Göteborg', 'name' => 'Anders Björk', 'date' => '2019-04-08', 'placeadress' => 'Axel Dahlströms torg 3', ),
2 => array ( 'id' => '230', 'place_id' => 'Axelhuset Göteborg', 'name' => 'Black Jack', 'date' => '2019-04-08', 'placeadress' => 'Axel Dahlströms torg 3', ),
3 => array ( 'id' => '227', 'place_id' => 'Arosdansen Syrianska Kulturcentret', 'name' => 'BarraBazz', 'date' => '2019-05-08', 'placeadress' => 'Narvavägen 90', ),
4 => array ( 'id' => '228', 'place_id' => 'Aspåsnäset', 'name' => 'Blender', 'date' => '2019-05-25', 'placeadress' => 'Aspåsnäset 167', ),
5 => array ( 'id' => '226', 'place_id' => 'Arenan Västervik Resort', 'name' => 'Blender', 'date' => '2019-06-29', 'placeadress' => 'Lysingsvägen', ),
6 => array ( 'id' => '222', 'place_id' => 'Alingsåsparken', 'name' => 'Bendéns', 'date' => '2019-07-16', 'placeadress' => 'Folkparksgatan 3A', ),
7 => array ( 'id' => '223', 'place_id' => 'Alingsåsparken', 'name' => 'Charlies', 'date' => '2019-07-16', 'placeadress' => 'Folkparksgatan 3A', ),
8 => array ( 'id' => '224', 'place_id' => 'Allhuset Södertälje', 'name' => 'Cedrix', 'date' => '2019-07-16', 'placeadress' => 'Barrtorpsvägen 1A', ), )
I want to update the "name" with an array of names everytime that place_id and date are the same.
This is the output I want:
Array (
[0] =>
Array ( [id] => 225 [place_id] => Alviks Kulturhus [name] => BarraBazz [date] => 2019-03-19 [placeadress] => Gustavslundsvägen 1 )
[1] =>
Array ( [id] => 229 [place_id] => Axelhuset Göteborg [name] => Array([0] => Anders Björk [1] => Black Jack ) [date] => 2019-04-08 [placeadress] => Axel Dahlströms torg 3 )
[3] =>
Array ( [id] => 227 [place_id] => Arosdansen Syrianska Kulturcentret [name] => BarraBazz [date] => 2019-05-08 [placeadress] => Narvavägen 90 )
[4] =>
Array ( [id] => 228 [place_id] => Aspåsnäset [name] => Blender [date] => 2019-05-25 [placeadress] => Aspåsnäset 167 )
[5] =>
Array ( [id] => 226 [place_id] => Arenan Västervik Resort [name] => Blender [date] => 2019-06-29 [placeadress] => Lysingsvägen )
[6] =>
Array ( [id] => 222 [place_id] => [Alingsåsparken] [name] => Array([0] => Bendéns [1] => Charlies) [date] => 2019-07-16 [placeadress] => Folkparksgatan 3A )
[8] =>
Array ( [id] => 224 [place_id] => Allhuset Södertälje [name] => Cedrix [date] => 2019-07-16 [placeadress] => Barrtorpsvägen 1A ) )
Here is my updated code
$sql = "SELECT `schedule`.`id`,`schedule`.`place_id`,`schedule`.`name`,`schedule`.`date`,`places`.`placeadress` FROM `schedule` INNER JOIN `places` ON `schedule`.`place_id`=`places`.`place_id` ORDER BY `date`";
$stmt = $db -> prepare($sql);
$stmt -> execute();
$ArraySchedule = $stmt->fetchAll(PDO::FETCH_ASSOC);
var_export($ArraySchedule);
$DatePlace = array();
foreach ($ArraySchedule as $key => $Schedule){
$Arrayquery = "SELECT `schedule`.`id`,`schedule`.`place_id`,`schedule`.`name`,`schedule`.`date`,`places`.`placeadress` FROM `schedule` INNER JOIN `places` ON `schedule`.`place_id`=`places`.`place_id` WHERE `schedule`.`date`= :date_ AND `schedule`.`place_id` = :place_id ORDER BY `date`";
$ArrayStmt = $db->prepare($Arrayquery);
$ArrayStmt -> execute(array(":date_" => $Schedule['date'],":place_id" => $Schedule['place_id']));
//Getting every $Schedule that has the same date and place_id
if($ArrayStmt->rowCount() > 1){
//Here i want two update the name inside
//$ArrayArraySchedule with an array of names
//that has the same place and date?
}
}
print_r($ArraySchedule);

ElasticSearch - How to return data from elastic search with not empty value?

I've got a problem with eliminating empty values from a document of one of my index.
$params = [
"scroll" => "30s", // how long between scroll requests. should be small!
"size" => 1,
"index" => $eddIndex,
'type' => $eddIndexType
];
$response = $client->search ( $params );
while ( isset ( $response ['hits']['hits'] ) && count ( $response['hits']['hits'] ) > 0 ) {
$scroll_id = $response ['_scroll_id'];
$response = $client->scroll ( [
"scroll_id" => $scroll_id,
"scroll" => "30s"
] )
;
This will Return
Array
(
[_scroll_id] => cXVlcnlUaGVuRmV0Y2g7NTs0NTY0NDM6di1Bd2x4X0ZSaTJ5cnpVUkFHb3FRdzs0NTY0NDQ6di1Bd2x4X0ZSaTJ5cnpVUkFHb3FRdzs0NTY0NDY6di1Bd2x4X0ZSaTJ5cnpVUkFHb3FRdzs0NTY0NDc6di1Bd2x4X0ZSaTJ5cnpVUkFHb3FRdzs0NTY0NDU6di1Bd2x4X0ZSaTJ5cnpVUkFHb3FRdzswOw==
[took] => 12
[timed_out] =>
[_shards] => Array
(
[total] => 5
[successful] => 5
[failed] => 0
)
[hits] => Array
(
[total] => 378887
[max_score] => 1
[hits] => Array
(
[0] => Array
(
[_index] => index
[_type] => edd
[_id] => 13038
[_score] => 1
[_source] => Array
(
[reason] =>
[booking_date] => 2013-05-03T18:30:00.000Z
[booking_location] => ABC
[scan_edd] =>
[call_status] => Call
[patient_name] => ABCD
[#version] => 1
[effective_edd] =>
[id] => 13038
[email] => xxxxxxxxx#gmail.com
[last_known_edd] =>
[booking_amount] => 8000
[address] => xxxxxxxxxxxxxxxxx
[eda] => 2013-09-09T18:30:00.000Z
[edd] =>
[mpi] => xxxxxxx
[mobile] => xxxxxxx
[statuss] => Open Payment
[tags] => Array
(
[0] => edd
)
[last_consult_by] => Dr. XXXX [site] => BLR
[#timestamp] => 2018-07-06T06:30:39.040Z
[patient_id] => 75220
[last_consult_on] => 2014-02-28T18:30:00.000Z
[ip_booking] => XYX Package
[is_converted] => 0
)
)
)
)
)
If you look at my output, There is a field [effective_edd] returning empty.
I wanted to return data with [effective_edd] not empty.
I'm referring to the below document https://packagist.org/packages/elasticsearch/elasticsearch
You need to add a query that checks for the existence of the field to your scroll request:
$params = [
"scroll" => "30s", // how long between scroll requests. should be small!
"size" => 1,
"index" => $eddIndex,
'type' => $eddIndexType,
'body' => [
'query' => [
'exists' => [
'field' => 'effective_edd'
]
]
]
];

How to get the highest and lowest Values and sum from Multidimensional array in PHP

I have tried using this example here Return index of highest value in an array
But that does not go into a multi dimensional Array
I have tried ARRAY_COLUMN(), array_values(), array_shift, Max and Min but they are not getting the info i need
I want to be able to loop thru and get to:
[pricing]
then Check pricing to see which is the highest and lowest in the nested array
so like below which total was the Highest and lowest trades on these dates
[2017-09-22]
[2017-09-23]
obviously [2017-09-23] is a simple one, i just dint want to add much more code for ppl helping to go thru.
The Array i create looks like this:
Array
(
[2017-09-23] => Array
(
[0] => Array
(
[timestamp] => 1506169387000
[pricing] => 9.5470
[qty] => 25
[total] => 238.675
[date] => 2017-09-23
)
)
[2017-09-22] => Array
(
[0] => Array
(
[timestamp] => 1506093083000
[pricing] => 9.6300
[qty] => 25
[total] => 240.75
[date] => 2017-09-22
)
[1] => Array
(
[timestamp] => 1506077220000
[pricing] => 8.7190
[qty] => 13
[total] => 113.347
[date] => 2017-09-22
)
[2] => Array
(
[timestamp] => 1506077109000
[pricing] => 8.6800
[qty] => 83
[total] => 720.44
[date] => 2017-09-22
)
[3] => Array
(
[timestamp] => 1506065258000
[pricing] => 8.7100
[qty] => 25
[total] => 217.75
[date] => 2017-09-22
)
)
in the example above i would like it to Create a new array with only the following
date -> last timestamp -> Highest pricing -> Lowest lowest -> Total of all Totals -> first Timestamp
EDIT: the last and first Timestamp are basically the first and last index so in this case:
[timestamp] => 1506093083000 and [timestamp] => 1506065258000
or Index [0] and index [3]
The array from your question:
$array = array (
'2017-09-23' =>
array (
0 =>
array (
'timestamp' => '1506169387000',
'pricing' => '9.5470',
'qty' => '25',
'total' => '238.675',
'date' => '2017-09-23',
),
),
'2017-09-22' =>
array (
0 =>
array (
'timestamp' => '1506093083000',
'pricing' => '9.6300',
'qty' => '25',
'total' => '240.75',
'date' => '2017-09-22',
),
1 =>
array (
'timestamp' => '1506077220000',
'pricing' => '8.7190',
'qty' => '13',
'total' => '113.347',
'date' => '2017-09-22',
),
2 =>
array (
'timestamp' => '1506077109000',
'pricing' => '8.6800',
'qty' => '83',
'total' => '720.44',
'date' => '2017-09-22',
),
3 =>
array (
'timestamp' => '1506065258000',
'pricing' => '8.7100',
'qty' => '25',
'total' => '217.75',
'date' => '2017-09-22',
),
),
);
To get the values maybe you can use array_map and with this the function array_column is the key of all, try with this:
$values = array_map(function($dates) {
$timestamps = array_column($dates, 'timestamp');
$pricings = array_column($dates, 'pricing');
return [
'max_pricing' => max($pricings),
'lowest_pricing' => min($pricings),
'total_of_totals' => array_sum(array_column($dates, 'total')),
'first_timestamp' => reset($timestamps),
'last_timestamp' => end($timestamps),
];
}, $array);
$values is an array with the filter values that you need:
Array
(
[2017-09-23] => Array
(
[max_pricing] => 9.5470
[lowest_pricing] => 9.5470
[total_of_totals] => 238.675
[first_timestamp] => 1506169387000
[last_timestamp] => 1506169387000
)
[2017-09-22] => Array
(
[max_pricing] => 9.6300
[lowest_pricing] => 8.6800
[total_of_totals] => 1292.287
[first_timestamp] => 1506093083000
[last_timestamp] => 1506065258000
)
)
EDIT
Get the pricing of the [first_timestamp] and [last_timestamp]
$values = array_map(function($dates) {
$timestamps = array_column($dates, 'timestamp');
$pricings = array_column($dates, 'pricing');
return [
'max_pricing' => max($pricings),
'lowest_pricing' => min($pricings),
'total_of_totals' => array_sum(array_column($dates, 'total')),
'first_timestamp' => [
'value' => reset($timestamps),
'pricing' => $pricings[each($timestamps)['key']]
],
'last_timestamp' => [
'value' => end($timestamps),
'pricing' => $pricings[each($timestamps)['key']]
]
];
}, $array);
I added an array to both timestamps with the value of these and the pricing.
Array
(
[2017-09-23] => Array
(
[max_pricing] => 9.5470
[lowest_pricing] => 9.5470
[total_of_totals] => 238.675
[first_timestamp] => Array
(
[value] => 1506169387000
[pricing] => 9.5470
)
[last_timestamp] => Array
(
[value] => 1506169387000
[pricing] => 9.5470
)
)
[2017-09-22] => Array
(
[max_pricing] => 9.6300
[lowest_pricing] => 8.6800
[total_of_totals] => 1292.287
[first_timestamp] => Array
(
[value] => 1506093083000
[pricing] => 9.6300
)
[last_timestamp] => Array
(
[value] => 1506065258000
[pricing] => 8.7100
)
)
)

Extracting values from JSON in PHP

I am currently experimenting with the Discogs API, using PHP. My query against their API is returned as JSON, which I can decoding using:
$trackMeta = json_decode($trackMeta, true);
I'd then like to be able to access certain elements within the data that is returned. Using print_r($trackMeta);outputs the below data:
Array ( [pagination] => Array ( [per_page] => 1 [pages] => 7 [page] => 1 [urls] => Array ( [last] => http://api.discogs.com/database/search?artist=siren&q=snorkel&per_page=1&page=7 [next] => http://api.discogs.com/database/search?artist=siren&q=snorkel&per_page=1&page=2 ) [items] => 7 ) [results] => Array ( [0] => Array ( [style] => Array ( [0] => Drum n Bass ) [thumb] => http://api-img.discogs.com/cf1HxM29IXQKNsSdrwYioa0uEeI=/fit-in/150x150/filters:strip_icc():format(jpeg):mode_rgb()/discogs-images/R-3581480-1336678182-5777.jpeg.jpg [format] => Array ( [0] => Vinyl [1] => 12" [2] => 45 RPM ) [country] => UK [barcode] => Array ( ) [uri] => /Siren-21-Vicious-Circle-Snorkel-SPY-Remix-Solitude/master/433189 [community] => Array ( [want] => 66 [have] => 81 ) [label] => Array ( [0] => Siren Records ) [catno] => SIREN001 [year] => 2012 [genre] => Array ( [0] => Electronic ) [title] => Siren (21) / Vicious Circle (3) - Snorkel (S.P.Y. Remix) / Solitude [resource_url] => http://api.discogs.com/masters/433189 [type] => master [id] => 433189 ) ) )
When trying to use a foreach loop on $trackMeta, I can only return 171 which I believe relates to per_page pages and page.
How can I access data deeper in this array? For example values such as thumb or year or genre?
$trackMeta is an associative array:
$trackMeta = array (
'pagination' => array (
'per_page' => 1,
'pages' => 7,
'page' => 1,
'urls' => array (
'last' => 'http://api.discogs.com/database/search?artist=siren&q=snorkel&per_page=1&page=7',
'next' => 'http://api.discogs.com/database/search?artist=siren&q=snorkel&per_page=1&page=2'
),
'items' => 7
),
'results' => array (
0 => array (
'style' => array (
0 => 'Drum n Bass'
),
'thumb' => 'http://api-img.discogs.com/cf1HxM29IXQKNsSdrwYioa0uEeI=/fit-in/150x150/filters:strip_icc():format(jpeg):mode_rgb()/discogs-images/R-3581480-1336678182-5777.jpeg.jpg',
'format' => array (
0 => 'Vinyl',
1 => '12"',
2 => '45 RPM'
),
'country' => 'UK',
'barcode' => array ( ),
'uri' => '/Siren-21-Vicious-Circle-Snorkel-SPY-Remix-Solitude/master/433189',
'community' => array (
'want' => 66,
'have' => 81
),
'label' => array (
0 => 'Siren Records'
),
'catno' => 'SIREN001',
'year' => 2012,
'genre' => array (
0 => 'Electronic'
),
'title' => 'Siren (21) / Vicious Circle (3) - Snorkel (S.P.Y. Remix) / Solitude',
'resource_url' => 'http://api.discogs.com/masters/433189',
'type' => 'master',
'id' => 433189
)
)
);
For example, you can access thumb with the following code:
print_r($trackMeta['results'][0]['thumb']);

MongoDB Aggregation PHP, Group by Days

I have the db with the following format
Array
(
[_id] => MongoId Object
(
[$id] => 53f4bf0e8db0d31b0ba802df
)
[userSession] => 580929792589634763f964479eee8721
[pageEnteredDate] => 1408548587
[pageLeftDate] => 1408548622
[userName] => User 1
[userId] => 33657
[pageView] => monitoring patients
[pageActions] => []
[pageTag] => 1-3-16-131-315
[timeSpent] => 35
)
Array
(
[_id] => MongoId Object
(
[$id] => 53f3d7008db0d33e61cae841
)
[userSession] => e04e5081c9482654030bacf3c8c90b21
[pageEnteredDate] => 1408488536
[pageLeftDate] => 1408489216
[userName] => user 2
[userId] => 4278
[pageView] => Surgery Staff
[pageActions] => [["BUTTON","Comment",1408488701],["A","Discussion",1408488712]]
[pageTag] => 1-3-5-148
[timeSpent] => 680
)
Array
(
[_id] => MongoId Object
(
[$id] => 53f3d7008db0d33gj1cae841
)
[userSession] => e04e5081c9482654030bahjhc8c90b21
[pageEnteredDate] => 1408488536
[pageLeftDate] => 1408489216
[userName] => user 3
[userId] => 428
[pageView] => Surgery Staff
[pageActions] => [["BUTTON","Comment",1408488701],["A","Discussion",1408488712]]
[pageTag] => 1-3-5-148
[timeSpent] => 680
)
pageEnteredDate is the date that i want to use
I want to group the data by pagetag and day. I mean on one day i should get the same pageTag only once.
So, from those 3 arrays it should display only 2 because 2 have the same pageTag and are on the same day.
Thanks
***code used
$result = $this->collection->aggregate(
array(
array(
'$group' => array(
'_id'=> array( 'pageTag' => '$pageTag','day' => array('$subtract' => array('$pageEnteredDate', 86400))),
'timeSpent' => array( '$sum' => '$timeSpent' ),
'lastView' => array( '$max' => '$pageEnteredDate' )
)
),
array('$skip' => 0),
array('$limit' => 20)
)
);
Your "date" values appear just to be numbers derived from epoch timestamps ( without the milliseconds ). But all you really want to do here is apply $group via the aggregation framework, and a little date math to group by "day":
$result = $collection->aggregate(array(
array(
'$group' => array(
'_id' => array(
'pageTag' => 'pageTag',
'day' => array(
'$subtract' => array(
'$pageEnteredDate',
array('$mod' => array(
'$pageEnteredDate',
60 * 60 * 24
))
)
)
),
'timeSpent' => array( '$sum' => '$timeSpent' ),
'lastView' => array( '$max' => '$pageEnteredDate' )
)
)
));
That basically says to group on both the "pageTag" values and using the "pageEnteredDate" to apply the math that essentially rounds the timestamp to the current day, so all values within the same day are the same.
You haven't said exactly what it is that you want to "group" here, so the examples are given of applying a $sum to the "timeSpent" value and using $max to identify the last timestamp value recorded on that day.
You can use any of the "grouping operators" in this way to suit your needs

Categories