Laravel 8查询构建器去重后分页计数错误的解决方法
解决Laravel 8中分类产品查询去重后分页计数错误的问题
问题原因
你遇到的问题本质是:通过join关联分类和产品中间表时,若一个产品同时属于目标父分类和多个子分类,会生成多条重复的产品记录。虽然distinct()能在最终结果里去重,但Laravel的paginate()方法默认执行的总数统计查询(count(*))并没有考虑去重逻辑,导致分页的总页数是基于去重前的记录数计算的,自然会出错。
推荐解决方案:先获取目标分类ID集合,再关联查询
这种方法从根源避免了重复记录的产生,性能更优,分页计数也会自动正确。
- 先获取指定分类及其所有子分类的ID集合
// 假设你的分类模型是Category $categoryIds = Category::where('id', $id) ->orWhere('parent_id', $id) ->pluck('id');
- 使用
whereHas关联查询产品(Eloquent ORM方式)
$products = Product::whereHas('categories', function ($query) use ($categoryIds) { $query->whereIn('category_id', $categoryIds); })->paginate(30);
如果要用查询构建器,也可以用whereExists实现:
$products = DB::table('products') ->whereExists(function ($query) use ($categoryIds) { $query->select(DB::raw(1)) ->from('category_product') ->whereColumn('category_product.product_id', 'products.id') ->whereIn('category_product.category_id', $categoryIds); }) ->paginate(30);
备选方案:手动修正分页的总计数
如果一定要保留原有的join逻辑,需要手动计算去重后的总记录数,再覆盖分页实例的总数:
- 计算去重后的总条数
$total = DB::table('products') ->join('category_product', 'products.id', '=', 'category_product.product_id') ->join('categories', 'category_product.category_id', '=', 'categories.id') ->where(function ($query) use ($id) { // 用闭包包住where/orWhere,避免后续加条件时逻辑混乱 $query->where('categories.id', $id) ->orWhere('categories.parent_id', $id); }) ->select('products.id') ->distinct() ->count();
- 获取分页数据并修正总数
$products = DB::table('products') ->join('category_product', 'products.id', '=', 'category_product.product_id') ->join('categories', 'category_product.category_id', '=', 'categories.id') ->where(function ($query) use ($id) { $query->where('categories.id', $id) ->orWhere('categories.parent_id', $id); }) ->select('products.*') ->distinct() ->paginate(30); // 覆盖分页实例的总记录数 $products->setTotal($total);
内容的提问来源于stack exchange,提问作者Ngọc Đồ Đinh
相关产品推荐
相关产品推荐

