Laravel 5.4中如何先取最新100条数据再重新排序并忽略首次排序?
解决Laravel中先取最新100条再排序取前5的问题
嘿,我明白你遇到的问题了——你的Query Builder链式调用没有按照预期逻辑执行,因为还没触发查询就修改了排序和限制条件,导致最终SQL完全偏离需求。先给你拆解问题,再给出几种靠谱的解决方案:
为什么你的代码失效?
你写的这段代码:
$lastHundredPost = Post::orderBy('id', 'desc')->take(100); $post = $lastHundredPost->orderBy('likecount', 'desc')->take(2)->get();
本质是在构建同一条SQL语句,并没有先执行“取100条”的操作。take(2)会直接覆盖之前的take(100),两次orderBy会合并成ORDER BY id DESC, likecount DESC,最终生成的SQL是直接从全表中按id+likecount排序取前2条,完全不是你想要的“先取最新100条,再在其中排序”的逻辑。
解决方案一:用Collection处理(最直观)
先把最新100条帖子取出生成Laravel集合,再用集合的排序方法处理,逻辑清晰,适合100条这种小数据量:
// 第一步:获取最新100条帖子的集合(这里已经执行了查询) $lastHundredPosts = Post::orderBy('id', 'desc')->take(100)->get(); // 第二步:在集合中按点赞数降序排序,取前5条 $topLikedPosts = $lastHundredPosts->sortByDesc('likecount')->take(5); // 如果要按浏览量或者举报量排序,只需要替换参数即可: // $topViewedPosts = $lastHundredPosts->sortByDesc('viewcount')->take(5); // $topReportedPosts = $lastHundredPosts->sortByDesc('reportcount')->take(5);
这种方法代码易读,集合方法还支持更复杂的排序逻辑(比如多字段组合排序),完全满足你的需求。
解决方案二:用子查询在数据库层处理
如果你想把整个逻辑放在数据库层面完成(比如未来数据量更大,但100条其实集合处理完全够用),可以用子查询实现:
$topPosts = Post::fromSub(function ($query) { // 子查询:先获取最新的100条帖子 $query->select('*') ->from('posts') ->orderBy('id', 'desc') ->take(100); }, 'latest_posts') // 在子查询结果中按点赞数降序排序,取前5 ->orderBy('likecount', 'desc') ->take(5) ->get();
这种方式会生成嵌套SQL,数据库会先执行子查询得到100条数据,再对这100条排序取前5,和你的需求完全匹配。
解决方案三:用whereIn查询(另一种数据库层实现)
先获取最新100条帖子的ID,再通过ID筛选并排序:
// 第一步:获取最新100条帖子的ID数组 $latestPostIds = Post::orderBy('id', 'desc')->take(100)->pluck('id')->toArray(); // 第二步:根据ID筛选,并按点赞数排序取前5 $topPosts = Post::whereIn('id', $latestPostIds) ->orderBy('likecount', 'desc') ->take(5) ->get();
这种方法和子查询效果类似,代码也比较直观,适合习惯用whereIn的场景。
内容的提问来源于stack exchange,提问作者Agil
相关产品推荐
相关产品推荐

