Laravel关联查询问题:如何实现每个分类取2个品牌、每个品牌取5个指定标签产品
Laravel关联查询实现「每个分类下2个品牌、每个品牌下5个产品」的解决方案
问题原因
你当前的代码中,在with闭包里直接使用limit()会导致全局限制:Laravel预加载关联时,会先查询所有父模型的关联ID,再批量查询关联数据,此时的limit(2)会限制所有分类总共返回2个品牌,limit(5)会限制所有品牌总共返回5个产品,而非每个父模型下的数量限制。
解决方案
以下两种方法可实现「每个分类下2个带标签品牌、每个品牌下5个带标签产品」的需求:
方法一:子查询限制(推荐,性能更优)
通过whereIn结合子查询,为每个父模型单独限制关联数据的数量,避免全局限制问题:
$tagKey = $tag->key; $categories = Category::where('tagkey', $tagKey) ->with(['brands' => function ($query) use ($tagKey) { // 每个分类下取前2个带标签的品牌 $query->where('tagkey', $tagKey) ->whereIn('id', function ($subQuery) use ($tagKey) { $subQuery->select('id') ->from('brands') ->whereColumn('category_id', 'categories.id') // 关联当前分类ID ->where('tagkey', $tagKey) ->orderBy('id') // 可根据业务需求调整排序字段 ->limit(2); }) ->with(['products' => function ($productQuery) use ($tagKey) { // 每个品牌下取前5个带标签的产品 $productQuery->where('tagkey', $tagKey) ->whereIn('id', function ($subQuery) use ($tagKey) { $subQuery->select('id') ->from('products') ->whereColumn('brand_id', 'brands.id') // 关联当前品牌ID ->where('tagkey', $tagKey) ->orderBy('id') ->limit(5); }); }); }]) ->get();
原理:子查询通过whereColumn关联父模型(分类/品牌)的ID,确保每个父模型单独执行一次限制查询,返回该父模型下的前N条关联数据。
方法二:逐个加载关联(适合小数据量场景)
先获取所有符合条件的分类,再逐个为每个分类加载指定数量的品牌,每个品牌加载指定数量的产品:
$tagKey = $tag->key; // 先获取所有带标签的分类 $categories = Category::where('tagkey', $tagKey)->get(); // 逐个加载每个分类的关联数据 $categories->each(function ($category) use ($tagKey) { $category->load([ 'brands' => function ($query) use ($tagKey) { // 当前分类下取2个带标签的品牌,并加载其产品 $query->where('tagkey', $tagKey)->limit(2)->load([ 'products' => function ($productQuery) use ($tagKey) { $productQuery->where('tagkey', $tagKey)->limit(5); } ]); } ]); });
注意:这种方法会产生N+1次查询(N为分类数量),数据量较大时可能影响性能,仅推荐小数据量场景使用。
内容的提问来源于stack exchange,提问作者Ali Nasser
相关产品推荐
相关产品推荐

