悠悠楠杉
Laravel教程:使用whereIn实现多分类文章高效筛选
当我们需要查询多个分类下的文章时,直觉上可能会想到使用多个 where 条件拼接,或者循环遍历每个分类单独查询。但这些方式不仅效率低下,还容易造成 N+1 查询问题,严重影响性能。更优雅且高效的方案是利用 Laravel 的 whereIn 方法结合关联查询来实现。
在 Laravel 模型中,我们可以在 Article 模型里定义与分类的多对多关系:
php
// app/Models/Article.php
public function categories()
{
return $this->belongsToMany(Category::class, 'article_category');
}
接着,在控制器中接收前端传递的分类 ID 数组。例如,用户选择了 ID 为 1、3、5 的三个分类,我们希望获取这三个分类下的所有文章。
php
// app/Http/Controllers/ArticleController.php
public function index(Request $request)
{
$categoryIds = $request->input('categories', []);
$query = Article::with('categories')->latest();
if (!empty($categoryIds)) {
$query->whereHas('categories', function ($q) use ($categoryIds) {
$q->whereIn('categories.id', $categoryIds);
});
}
$articles = $query->paginate(10);
return view('articles.index', compact('articles'));
}
这里的关键在于 whereHas 与 whereIn 的组合使用。whereHas 允许我们基于关联关系进行筛选,而 whereIn 则能一次性匹配多个分类 ID,避免了多次数据库查询。这种方式不仅代码简洁,而且数据库层面可以通过索引优化查询速度。
进一步优化时,我们可以考虑缓存机制。对于不频繁变动的分类文章列表,可以将结果缓存一段时间,减少数据库压力。例如使用 Laravel 的 Cache::remember 方法:
php
$articles = Cache::remember("articles.category." . md5(json_encode($categoryIds)), 3600, function () use ($categoryIds) {
return Article::with('categories')
->when(!empty($categoryIds), function ($q) use ($categoryIds) {
$q->whereHas('categories', fn($sub) => $sub->whereIn('categories.id', $categoryIds));
})
->latest()
->paginate(10);
});
此外,在实际项目中,我们还需要注意安全性。传入的 categoryIds 应该经过验证,确保每个 ID 都是合法的整数,防止恶意参数注入。可以使用 Laravel 的表单请求验证或直接在方法中过滤:
php
$categoryIds = collect($request->input('categories', []))
->map('intval')
->filter(fn($id) => $id > 0)
->toArray();
这样既保证了数据类型正确,也排除了无效值。
值得一提的是,whereIn 不仅适用于分类筛选,还可广泛应用于标签筛选、作者筛选、状态批量查询等场景。掌握其用法,能显著提升 Laravel 应用的数据处理能力。
