如何通过Laravel关联Eloquent预加载获取最新5位唯一评论者用户信息
问题根因
你当前使用的distinct('user_id')写法不符合SQL的执行逻辑:
- SQL里
DISTINCT是对查询返回的所有列的组合做去重,你同时查询了id(评论主键,每条唯一)、parent_id等字段,就算加上distinct也不会只按user_id去重,自然达不到预期效果。 - 如果直接用
groupBy('user_id'),在MySQL默认开启ONLY_FULL_GROUP_BY模式的情况下,会因为查询的非聚合字段没有出现在group by里报错,而且默认group by取的是最早的匹配数据,不是最新的评论对应的用户。
最优方案(数据库层面查询,性能最佳)
适配Laravel 8+版本,直接修改Post模型中的commenter_avatars关联方法即可:
public function commenter_avatars() { // 子查询:先取当前帖子下顶级评论中,每个user_id对应的最新一条评论ID $latestCommentIds = Comment::selectRaw('MAX(id) as id') ->whereColumn('post_id', 'posts.id') ->whereNull('parent_id') ->groupBy('user_id') ->orderBy('id', 'desc') ->limit(5); // 关联查询完整评论信息,预加载用户数据 return $this->hasMany(Comment::class) ->whereIn('id', $latestCommentIds) ->orderBy('id', 'desc') ->with('user:id,first_name,last_name,username,avatar'); }
你的控制器代码无需任何修改,原有逻辑即可正常返回预期结果。该方案所有逻辑都在数据库层面完成,即使单帖评论量很大也不会有性能问题。
备用方案(小数据量场景,写法更简洁)
如果单帖评论量长期低于100条,也可以用集合方法处理,代码更易维护:
public function commenter_avatars() { return $this->comments() ->whereNull('parent_id') ->with('user:id,first_name,last_name,username,avatar') ->latest() ->get() ->unique('user_id') ->take(5); }
注意该方案会先查询所有符合条件的评论再做去重截取,数据量大时性能损耗明显,仅适合小流量场景。
内容的提问来源于stack exchange,提问作者Anwar
相关产品推荐
相关产品推荐

