Laravel get most recent array item for each day in array

Tags: , , , ,



I’m trying to figure out the best way (whether I do this using the query builder or raw PHP) to get the most recent array item based on it’s created_at timestamp for a given day, in an array containing many days.

For example…

[
  [
    "name" => "John",
    "created_at" => "2021-01-17 23:00:00"
  ],
  [
    "name" => "Jane",
    "created_at" => "2021-01-17 20:00:00"
  ],
  [
    "name" => "Edward",
    "created_at" => "2021-01-16 19:00:00"
  ],
  [
    "name" => "Scott",
    "created_at" => "2021-01-16 17:00:00"
  ]
]

In the above I have two days, each day has an entry and I’d like to get the newest one for each of the days, e.g:

[
  [
    "name" => "John",
    "created_at" => "2021-01-17 23:00:00"
  ],
  [
    "name" => "Edward",
    "created_at" => "2021-01-16 19:00:00"
  ]
]

I currently have a query that gets everything between two dates…

$events = GoogleAnalytics::where('event_category', $category)
                        ->where('event_action', $action)
                        ->whereDate('period_from', '>=', $from)
                        ->whereDate('period_to', '<=', $to)
                        ->orderBy('created_at', 'desc')
                        ->get();

Answer

Using laravel collections helper you can pick latest record for each day first sort collection, then group your collection by day i.e grouping criteria and then using map pick first result from each group

$collection = $collection->sortByDesc('created_at');
$results = $collection->groupBy(function ($item, $key) {
    $date=  new DateTime($item['created_at']);
    return $date->format('Y-m-d');
});
$results = $results->map(function ($item, $key) {
    return $item[0];
});

Result set will look like as

Array
(
    [2021-01-17] => Array
        (
            [name] => John
            [created_at] => 2021-01-17 23:00:00
        )

    [2021-01-16] => Array
        (
            [name] => Edward
            [created_at] => 2021-01-16 19:00:00
        )

)

DEMO

Or another shorter version would be group , map + sort

$results = $collection->groupBy(function ($item, $key) {
    $date=  new DateTime($item['created_at']);
    return $date->format('Y-m-d');
});
$results = $results->map(function ($item, $key) {
    return $item->sortByDesc('created_at')->first();
});


Source: stackoverflow