You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel中正确查询并拼接当前用户的全部往来会话消息

问题分析

你现有两种SQL写法都无法实现按会话分组的需求,问题如下:

  • 不带GROUP BY的查询可以拉取所有属于当前用户的消息,但数据是平铺状态,没有会话归属标识,自然无法按会话整合
  • 带GROUP BY的写法逻辑完全错误,仅按sender_id分组只会随机返回每个发送者的一条消息,拿不到完整会话内容,同时如果数据库开启ONLY_FULL_GROUP_BY模式会直接抛出语法错误

该需求完全可以通过Laravel框架实现,具体方案如下:


1. 核心实现逻辑

按会话分组的核心是给每条消息生成统一的会话标识:同一对用户的往来消息,不管谁是发送方谁是接收方,生成的会话标识完全一致。
通用规则为:将sender_id和receiver_id按数值大小排序后拼接,比如当前用户ID为1,和ID为2的用户往来时,不管是1发2还是2发1,会话标识都为1_2,即可将所有同会话的消息归为一组。


2. 原生SQL实现参考

如果需要直接用SQL查询,可以用以下写法拿到带会话标识的所有消息:

SELECT 
    sender_id,
    receiver_id,
    message,
    created_at,
    CONCAT(LEAST(sender_id, receiver_id), '_', GREATEST(sender_id, receiver_id)) as conversation_key
FROM messages 
WHERE sender_id = 1 OR receiver_id = 1
ORDER BY created_at ASC;

查询结果拿到后按conversation_key字段分组即可得到所有会话内容。


3. Laravel框架实现方案

3.1 先定义Message模型

// app/Models/Message.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Message extends Model
{
    protected $fillable = ['sender_id', 'receiver_id', 'message'];
}

3.2 获取所有消息并按会话分组

借助Laravel集合的分组方法可以非常便捷的完成需求:

// 取当前登录用户ID
$currentUserId = auth()->id();

$messageGroups = Message::where('sender_id', $currentUserId)
    ->orWhere('receiver_id', $currentUserId)
    ->orderBy('created_at', 'asc')
    ->get()
    // 按会话标识分组
    ->groupBy(function ($item) use ($currentUserId) {
        // 取当前会话的对方用户ID
        $oppositeId = $item->sender_id === $currentUserId ? $item->receiver_id : $item->sender_id;
        // 生成统一的会话标识
        return min($currentUserId, $oppositeId) . '_' . max($currentUserId, $oppositeId);
    });

最终返回的$messageGroups为键值对结构:键是会话标识,值是对应会话下按时间正序排列的所有消息集合,可直接用于前端会话列表、会话详情的渲染。

3.3 扩展:获取会话列表(每个会话仅显示最新一条消息)

如果是做消息首页的会话列表,不需要拉取所有历史消息,只需每个会话返回最新一条,可以用以下写法:

$currentUserId = auth()->id();

$conversationList = Message::selectRaw("*, CONCAT(LEAST(sender_id, receiver_id), '_', GREATEST(sender_id, receiver_id)) as conversation_key")
    ->where('sender_id', $currentUserId)
    ->orWhere('receiver_id', $currentUserId)
    ->orderBy('created_at', 'desc')
    ->get()
    ->unique('conversation_key') // 每个会话仅保留最新的一条消息
    ->values();

内容的提问来源于stack exchange,提问作者Նորայր Եղիազարյան

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 05:36:05