Skip to content
Advertisement

Laravel get most recent array item for each day in array

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();

Advertisement

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();
});
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement