2

Even though there are multiple questions like this I can't get my query to return the row with the most recent date with a group by.

I have the following table..

| message_id | from | to | created_at | status
----------------------------------------------
|    1       |   1  |  2 | 2017-04-06 |   1
|    2       |   1  |  2 | 2017-04-07 |   0
|    3       |   3  |  4 | 2017-04-06 |   1
|    4       |   3  |  4 | 2017-04-07 |   0
----------------------------------------------

and I'm tryin to get the rows with most recent date.

| message_id | from | to | created_at | status
----------------------------------------------
|    2       |   1  |  2 | 2017-04-07 |   0
|    4       |   3  |  4 | 2017-04-07 |   0

Currently this query returns the rows with the last recent date.

$messages = Message::where('to', Auth::id())
                    ->groupBy('from')
                    ->orderBy('created_at', 'DESC')
                    ->paginate(10);
SlyDave
  • 877
  • 11
  • 21
mattesj
  • 389
  • 1
  • 5
  • 18

6 Answers6

9

The problem is that the result set will be first grouped then ordered. You can use nested select to get what you want.

SQL Query:

SELECT t.* FROM (SELECT * FROM messages ORDER BY created_at DESC) t GROUP BY t.from

With Laravel:

$messages = Message::select(DB::raw('t.*'))
            ->from(DB::raw('(SELECT * FROM messages ORDER BY created_at DESC) t'))
            ->groupBy('t.from')
            ->get();

You just need to add your where() clauses.

Ivanka Todorova
  • 9,533
  • 15
  • 56
  • 97
4

You may replace groupBy with distinct, as it works in my case.

$messages = Message::where('to', Auth::id())
                ->orderBy('created_at', 'DESC')
                ->distinct('from')
                ->paginate(10);

Hope this helps.

sllim.Sam
  • 114
  • 5
3

If anyone is still looking for a short and Eloquent answer for using groupBy() with latest() just add unique() after get() like this...

$unreadMessages = Message::where('receiver_id', Auth::user()->id)
    ->where('read_at', null)
    ->latest()
    ->get()
    ->unique('user_id');
Aushraful
  • 59
  • 6
1

To get most recent record for each from you can use a self join

DB::table('message as m')
  ->select('m.*')
  ->leftJoin('message as m1', function ($join) {
        $join->on('m.from', '=', 'm1.from')
             ->whereRaw(DB::raw('m.created_at < m1.created_at'));
   })
  ->whereNull('m1.from')
  ->orderBy('m.created_at', 'DESC')
  ->paginate(10);

In SQL it will look like

select m.*
from message m
left join message m1 on m.from = m1.from
and m.created_at < m1.created_at
where m1.from is null
order by m.created_at desc

Laravel Eloquent select all rows with max created_at

M Khalid Junaid
  • 62,293
  • 9
  • 87
  • 115
0

You've got a date field in your example, not a datetime field, so the following is my preferred method:

# Mysql
select * from
  your_table
where date_field = (select max(date_field) from your_table)
// Laravel
YourModel:::query()->whereRaw('date_field = (select max(date_field) from your_table)')->get();
  • Note the above wont work as expected for datetime fields because the rows will have different timestamps, it'll likely just return the single latest row.
Lewis
  • 606
  • 8
  • 16
-1

You might also want to orderBy message_id as well

$messages = Message::where('to', Auth::id())
                    ->groupBy('from')
                    ->orderBy('created_at', 'DESC')
                    ->orderBy('message_id', 'DESC')
                    ->paginate(10);
Saad
  • 1,125
  • 1
  • 16
  • 34