Laravel 8中如何用groupBy获取带最新消息的患者列表
解决Laravel按patient_id分组获取患者信息及最新聊天消息的问题
问题原因分析
- 带
groupBy('patient_id')时,MySQL默认仅返回每组的第一条匹配记录,因此你只拿到单条患者数据,但由于关联逻辑正确,最新消息显示正常。 - 移除
groupBy后数据为空,大概率是Eloquent关联定义错误,或是查询时未正确加载关联关系,导致患者信息与聊天消息均无法被获取。
具体解决方案
方案一:子查询+关联表获取分组数据
通过子查询先筛选出每个患者的最新聊天记录时间,再关联聊天表和患者表获取完整数据:
$chatGroups = DB::table('chats') // 先分组获取每个患者的最新消息时间 ->select('patient_id', DB::raw('MAX(created_at) as latest_message_time')) ->groupBy('patient_id') // 关联子查询拿到对应最新消息的内容 ->joinSub(function ($query) { $query->from('chats') ->select('patient_id', 'message', 'created_at') ->orderBy('created_at', 'desc'); }, 'latest_chats', function ($join) { $join->on('chats.patient_id', '=', 'latest_chats.patient_id') ->on('chats.latest_message_time', '=', 'latest_chats.created_at'); }) // 关联患者表获取患者信息 ->join('patients', 'chats.patient_id', '=', 'patients.id') // 选择需要返回的字段 ->select('patients.*', 'latest_chats.message as latest_message', 'latest_chats.created_at as message_time') ->get();
方案二:Eloquent关联+筛选最新消息
先确保Patient模型定义了正确的聊天关联:
// app/Models/Patient.php public function chats() { return $this->hasMany(Chat::class, 'patient_id'); }
然后通过关联闭包直接获取每个患者的最新一条聊天消息:
$patients = Patient::query() ->with(['chats' => function ($query) { $query->latest()->take(1); // 只取最新的一条消息 }]) ->whereHas('chats') // 仅保留有聊天记录的患者 ->get() ->filter(function ($patient) { return $patient->chats->isNotEmpty(); // 过滤掉无有效消息的患者(可选) });
这种方式会自动按患者分组,返回每个患者的完整信息及最新聊天消息。
方案三:修正GroupBy逻辑(适配MySQL严格模式)
若坚持使用groupBy,需保证select中的非聚合字段都加入groupBy(或关闭MySQL严格模式),同时正确关联患者表:
$chatGroups = DB::table('chats') ->join('patients', 'chats.patient_id', '=', 'patients.id') ->select( 'patients.*', 'chats.message as latest_message', DB::raw('MAX(chats.created_at) as latest_time') ) ->groupBy('patients.id', 'chats.message') // MySQL严格模式下需包含所有非聚合字段 ->orderBy('latest_time', 'desc') ->get();
注:此方案若同一患者存在相同内容的消息,可能出现重复分组,建议优先使用前两种方案。
内容的提问来源于stack exchange,提问作者Sajith Madhubashana
相关产品推荐
相关产品推荐

