Estou tentando buscar dados relacionados ao bate-papo usando o Eloquent no Laravel 11, mas estou com dificuldades para estruturar uma consulta otimizada usando relacionamentos ou junções do Eloquent.
Tenho duas tabelas MySQL:
- usuários -> id, nome_completo, foto_do_perfil
- chat_messages -> id, sender_id, receiver_id, mensagem, created_at, lida (0 = não lida, 1 = lida)
Resultado desejado: Quero buscar os seguintes dados para um remetente específico (sender_id = 1):
{
"user": {
"id": 1,
"full_name": "Sender Name",
"profile_pic": "sender profile pic url"
},
"chat_message": {
"unread": 3, // count of unread messages from sender_id = 1
"last_message": "whatever it was", // last message sent by sender_id = 1
"created_at": "last message's sent time"
}
}
Consultas brutas que funcionam:
// Fetch user details
SELECT id, full_name, profile_pic FROM users WHERE id = 196;
// Count unread messages from sender_id = 196
SELECT COUNT(id) FROM chat_messages WHERE read = 0 AND sender_id = 196 AND receiver_id = 197;
// Get last message from sender_id = 196
SELECT message, created_at
FROM chat_messages
WHERE sender_id = 196 AND receiver_id = 197
ORDER BY id DESC
LIMIT 1;
Minha pergunta:
Existe uma maneira eficiente de fazer isso usando relacionamentos ou junções do Eloquent em vez de várias consultas brutas?
Como posso otimizar isso para desempenho no Laravel 11?
Consulta adicional sobre junções: Como uma JOIN realmente funciona em detalhes?
O MySQL busca cada linha da Tabela 1, uma por uma, e depois procura uma linha correspondente na Tabela 2 antes de passar para a próxima linha?
Ou ele busca todos os resultados da Tabela 1 de uma vez e então os une à Tabela 2 com base em restrições? Qualquer ajuda ou insights seriam muito apreciados! Obrigado antecipadamente. 🙌
Tabela com dados fictícios para teste.
CREATE TABLE `chat_messages` (
`id` bigint(20) UNSIGNED NOT NULL,
`sender_id` bigint(20) UNSIGNED NOT NULL,
`receiver_id` bigint(20) UNSIGNED NOT NULL,
`message` text NOT NULL,
`read` tinyint(3) UNSIGNED NOT NULL DEFAULT 0,
`created_at` timestamp NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `chat_messages` (`id`, `sender_id`, `receiver_id`, `message`, `read`, `created_at`) VALUES
(1, 196, 197, 'Some message 1', 0, '2025-02-14 00:04:47'),
(2, 196, 197, 'Some message 2', 0, '2025-02-14 00:10:02'),
(3, 196, 197, 'Some message 3', 0, '2025-02-14 00:11:06'),
(4, 197, 196, 'Some message 4', 0, '2025-02-14 00:11:31'),
(5, 196, 197, 'Some message 5', 0, '2025-02-14 00:13:11'),
(6, 197, 196, 'Some message 6', 0, '2025-02-14 00:13:15'),
(7, 196, 197, 'Some message 7', 0, '2025-02-14 00:13:51'),
(8, 197, 196, 'Some message 8', 0, '2025-02-14 00:14:04'),
(9, 196, 197, 'Some message 9', 0, '2025-02-14 00:14:13'),
(10, 197, 196, 'Some message 10', 0, '2025-02-14 00:14:20'),
(11, 196, 197, 'Some message 11', 0, '2025-02-14 00:14:40'),
(12, 197, 196, 'Some message 12', 0, '2025-02-14 00:14:47'),
(13, 197, 196, 'Some message 13', 0, '2025-02-14 00:15:02'),
(14, 196, 197, 'Some message 14', 0, '2025-02-14 00:15:11'),
(15, 196, 197, 'Some message 15', 0, '2025-02-14 00:25:08'),
(16, 197, 196, 'Some message 16', 0, '2025-02-14 00:25:15'),
(17, 196, 197, 'Some message 17', 0, '2025-02-14 00:25:30'),
(18, 196, 197, 'Some message 18', 0, '2025-02-14 00:27:48'),
(19, 197, 196, 'Some message 19', 0, '2025-02-14 00:27:53'),
(20, 196, 197, 'Some message 20', 0, '2025-02-14 00:27:58'),
(21, 196, 197, 'Some message 21', 0, '2025-02-14 00:28:59'),
(22, 197, 196, 'Some message 22', 0, '2025-02-14 00:29:01'),
(23, 196, 197, 'Some message 23', 0, '2025-02-14 00:29:15'),
(24, 197, 196, 'last message from 197', 0, '2025-02-14 00:29:18'),
(25, 196, 197, 'last message from 196', 0, '2025-02-14 00:29:23');
Você pode fazer assim...
1. Mude seu
User.php(User Model)
assim...2. Defina o relacionamento no modelo ChatMessage (ou seja, ChatMessage.php)* assim...
Então, com base nisso
sender_id
,receiver_id
você pode buscar dados como estes.Como um JOIN realmente funciona em detalhes?
O MySQL não busca todas as linhas da Tabela 1 de uma vez. Em vez disso, ele itera sobre cada linha de
Table-1
e encontra linhas correspondentes emTable-2
. Se não houver índice,MySQL
ele varre todo oTable-2
para cada linha deTable-1
. Em seguida, passa para a próxima linha emtable-1
.