使用category_products中间表关联分类与产品,按分类取5个产品失败求助
问题分析
你的代码里在with('categoryProducts')的闭包中直接调用take(4),这会导致所有分类总共只返回4条categoryProducts记录,而不是每个分类返回对应数量的产品(你实际需要的是5条)。这是因为take()在预加载关联时是全局限制,而非针对每个父模型的关联限制。
解决方案
方法一:优化关联定义(推荐)
首先确保你的Category模型中定义了与Product的多对多关联(通过category_products中间表):
// Category.php public function products() { return $this->belongsToMany(Product::class, 'category_products'); }
然后定义一个专门用于获取Top5产品的关联:
// Category.php public function topProducts() { return $this->products() ->orderBy('sold', 'desc') ->take(5); }
最后修改查询代码:
$query = $this->getQuery(); $query->where('parent_id', '0') ->with('topProducts') ->whereHas('products'); // 过滤掉没有产品的分类 return $query->get();
方法二:预加载时使用子查询(适配多关联层级场景)
如果必须保留categoryProducts关联(比如需要中间表的额外字段),可以用子查询来实现每个分类取5条关联记录:
$query = $this->getQuery(); $query->where('parent_id', '0') ->with(['categoryProducts' => function ($q) { $q->with('product') ->orderBy('sold', 'desc') // 子查询限制每个分类的关联数量 ->whereIn('category_products.id', function ($sub) { $sub->select('id') ->from('category_products') ->whereColumn('category_id', 'categories.id') ->orderBy('sold', 'desc') ->take(5); }); }]) ->whereHas('categoryProducts'); return $query->get();
方法三:分批加载(适合小数据量场景)
如果数据量不大,也可以先获取分类,再逐个加载对应的关联产品,避免全局take()的问题:
$categories = $this->getQuery() ->where('parent_id', '0') ->whereHas('categoryProducts') ->get(); $categories->each(function ($category) { $category->load(['categoryProducts' => function ($q) { $q->with('product') ->orderBy('sold', 'desc') ->take(5); }]); }); return $categories;
注意:方法三会产生N+1查询(N为分类数量),数据量大时不推荐使用。
内容的提问来源于stack exchange,提问作者Wali
相关产品推荐
相关产品推荐

