Laravel Eloquent按特殊条件排序:分类搜索时优先展示匹配对应话题的新闻
Laravel Eloquent按特殊条件排序:分类搜索时优先展示匹配对应话题的新闻
嘿,我来帮你搞定这个排序需求!你的核心诉求是:搜索某个分类时,先把话题正好和搜索分类同名的新闻排在最前面,剩下的同分类新闻再跟在后面对吧?
其实实现起来很简单,我们只需要给符合话题匹配条件的新闻加一个「优先级标记」,然后按照这个标记排序就行。下面给你两种靠谱的实现方式:
方法一:用子查询实现排序(推荐,避免表连接的重复问题)
这种方式不需要额外的表连接,直接通过子查询判断当前新闻的话题是否匹配搜索词,然后按这个结果排序:
$search = 'TV series'; $query = News::with(['category_related', 'topic_related']) // 先筛选出包含目标分类的新闻 ->whereHas('category_related', function($q) use ($search) { $q->where('name', 'like', "%{$search}%"); }) // 核心排序逻辑:如果新闻的话题等于搜索词,优先级为1,否则为0,按优先级倒序 ->orderByRaw("( SELECT COUNT(*) FROM related_post_topic rpt JOIN topics t ON rpt.topic_id = t.id WHERE rpt.post_id = news.id AND t.name = ? ) DESC", [$search]) // 可选:优先级相同的新闻,可以按id倒序(对应你想要的News4→News3的顺序) ->orderBy('id', 'desc') ->paginate(20);
方法二:用表连接+临时字段排序
这种方式通过连接话题关联表和话题表,创建一个临时的优先级字段,再按这个字段排序:
$search = 'TV series'; $query = News::with(['category_related', 'topic_related']) ->whereHas('category_related', function($q) use ($search) { $q->where('name', 'like', "%{$search}%"); }) // 连接话题关联表和话题表,创建临时字段标记是否匹配 ->selectRaw('news.*, CASE WHEN topics.name = ? THEN 1 ELSE 0 END AS is_matching_topic', [$search]) ->join('related_post_topic', 'news.id', '=', 'related_post_topic.post_id') ->join('topics', 'related_post_topic.topic_id', '=', 'topics.id') // 先按优先级倒序,再按id倒序 ->orderBy('is_matching_topic', 'desc') ->orderBy('news.id', 'desc') // 去重,避免因多分类导致的重复记录 ->distinct() ->paginate(20);
为什么这样能解决你的问题?
拿你的例子来说:
- News4和News3的话题都是「TV series」,优先级标记为1,会排在前面;
- News5的话题是「crime」,优先级标记为0,会排在最后;
- 再加上
orderBy('id', 'desc'),News4(id4)就会在News3(id3)前面,正好符合你想要的顺序:News4 → News3 → News5。
注意哦:如果你的表名(比如related_post_topic、topics)和实际项目里不一样,记得改成你自己的表名~
备注:内容来源于stack exchange,提问作者Danilo
相关产品推荐
相关产品推荐

