It is returning only for a single user because of the WHERE clause:
->where('messages.from_id', $request->user_id)
Remove it and you should be fine.
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
i have two tables named users and message, I want to join both tables and get the last message from each user's conversation with user_name. My messages table having columns like from_id, to_id, messages, created_at.
Below is my code.
$chats = DB::table('users')
->leftJoin('messages', function($query)
{
$query->on('users.id', '=', 'messages.to_id')
->whereRaw('messages.id IN (select MAX(messages.id) from messages join users on users.id = messages.to_id group by users.id)');
})
->select('users.id as user_id', 'users.name', DB::raw('CONCAT("https://www.interwebs.co.in/puzzle/attach/", users.avatar) AS image') , 'users.mobile', 'messages.id', 'messages.from_id', 'messages.to_id', 'messages.body as message', 'messages.attachment', 'messages.seen as seen_count', 'messages.created_at')
->where('messages.from_id', $request->user_id)
->get();
My messages table is
| from_id | to_id | message | created_at |
| ---------| --------- | ---------| ------------------ |
| 1 | 2 | abc | 2022-02-04 10:55:34 |
| 2 | 1 | cdef | 2022-02-05 10:56:34 |
| 1 | 3 | defg | 2022-02-06 10:57:34 |
| 1 | 3 | hijk | 2022-02-07 10:58:34 |
| 1 | 2 | lmop | 2022-02-08 10:59:34 |
I have tried this but it is giving me the last message of each conversation of current logged in user and not others.
@Zafeer now it is clearer what you wanted.
If you accept a suggestion to avoid the loop and the unique just after the query:
$user_id = $request->user_id;
$chats = DB::table('messages')
->leftJoin('users as u1', 'messages.from_id', '=', 'u1.id')
->leftJoin('users as u2', 'messages.to_id', '=', 'u2.id')
->selectRaw('CASE WHEN u1.id = ? THEN u2.id ELSE u1.id END AS user_id', [$user_id])
->selectRaw('CASE WHEN u1.id = ? THEN u2.name ELSE u1.name END AS name', [$user_id])
->addSelect([
'messages.id',
'messages.from_id',
'messages.to_id',
'messages.body as message',
'messages.attachment',
'messages.created_at',
])
// When using OR with WHERE clauses, it is a nice idea to wrap
// them into a nested ->where(), as this the equivalent
// to wrap then into parenthesis on a SQL clause
// this way, if you need to add more WHERE clauses later,
// they won't be affected by these.
->where(function ($query) use ($user_id) {
$query->orWhere('messages.from_id', $user_id)
->orWhere('messages.to_id', $user_id);
})
->latest()
->limit(1) // avoid the unique call
->get();
You could replace the ->limit(1)->get() by a ->first() call.
I kept the ->limit(1)->get() as you might always be expecting a collection result.
Please or to participate in this conversation.