Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Impala44's avatar

How to get the last record of a day of date range

I have traffic table with many records during a day, and I need to get statistic for some date range, but only the last record of a day.

And I'm stuck a bit, because if I do like this

$startDate = date('Y-m-d', strtotime('2021-03-01')); $endDate = date('Y-m-d', strtotime('2021-03-24')); $records = Traffic::whereDate('created_at', '>=', $startDate)->whereDate('created_at', '<=', $endDate)->get();

That's how I see all records, but I need only for the of each day

$records = Traffic::all()->sortByDesc('created_at')->take(1)->toArray();

This give me just last record of table...

0 likes
8 replies
Braunson's avatar

Might I suggest using the whereBetween query then using Eloquent Collections to groupBy day, then pluck the last record for each (grouped) day?

Impala44's avatar
$records = Traffic::whereDate('created_at', '>=', $startDate)->whereDate('created_at', '<=',         $endDate)->get()->groupBy(function($item) {
                    return $item->created_at->format('Y-m-d');
                })->toArray();
        

foreach ($records as $key => $record){
       $records[$key] = array_slice($record, -1);
}

It works very well with an array, but how to do the same with Object, not array ? Could you please advice how to pluck the last record for each day without conversion to an array.

I'm just trying to learn how to write code correctly to have it possible to get an Object in my View, but not as an array.

Impala44's avatar
        $records = Traffic::whereDate('created_at', '>=', $startDate)->whereDate('created_at', '<=', $endDate)->get()->groupBy(function($item) {
        return $item->created_at->format('Y-m-d');
    });


        foreach ($records as $record){
            $arrayLength = count($record);
            $counter = 0;
            foreach ($record as $key => $item){
                $counter++;
                if ($counter != $arrayLength){
                    unset ($record[$key]);
                }
            }
        }

        $arrayResult = [];

        foreach ($records as $record){
            foreach ($record as $item){
                array_push($arrayResult, $item);
            }
        }

And now I send $arrayResult to my View.

Could you advise me how did the code should look like? This is confused me by this excessive rotation, and it seems that the code looks like a newbie code.

andrew_markhai's avatar
Level 1

@impala44 You can get ids of last rows for each day and then , by these ids, get all rows which you need:

select created_at, max(id)
from traffics
where created_at between '2020-01-01' and '2020-01-31'
group by created_at
Impala44's avatar

Could you tell me how to get these ids via Builder ?

$records = Traffic::select('created_at')->whereBetween('created_at', [$startDate, $endDate])->get()->groupBy(function($item) {
            return $item->created_at->format('Y-m-d');
        });

I tried like this, but have no idea how to get max id of each date

andrew_markhai's avatar

Try this:

Traffic::query()
            ->selectRaw('max(id) as id, created_at')
            ->whereBetween('created_at', ['2020-01-01', '2020-01-31'])
            ->groupBy('created_at')
            ->get()
			->pluck('id')
			->toArray()
Impala44's avatar

It's just show me all 25 records of the table

array:25 [▼
  0 => 1
  1 => 2
  2 => 3
  3 => 4
  4 => 5
  5 => 6
  6 => 7
  7 => 8
  8 => 9
  9 => 10
  10 => 11
  11 => 12
  12 => 13
  13 => 15
  14 => 16
  15 => 17
  16 => 18
  17 => 19
  18 => 20
  19 => 21
  20 => 22
  21 => 23
  22 => 24
  23 => 25
  24 => 26
]

If I do groupBy with created_at->format('Y-m-d'), it shows me an error

ErrorException stripos() expects parameter 1 to be string, object given

in Query \ Grammars \ Grammar :1163

$records = Traffic::query()
            ->selectRaw('max(id) as id, created_at')
            ->whereBetween('created_at', [$startDate, $endDate])
            ->groupBy(function($item) {
                return $item->created_at->format('Y-m-d');
            })
            ->get()
            ->pluck('id')
            ->toArray();

andrew_markhai's avatar

Oh, yes, created_at is datetime, not date. Try casting:

Traffic::query()
            ->selectRaw('max(id) as id, CAST(created_at AS DATE) as date')
            ->whereBetween('created_at', ['2020-01-01', '2020-01-31'])
            ->groupByRaw('CAST(created_at AS DATE)')
            ->get()
            ->toArray();

Please or to participate in this conversation.