怎么优雅的处理分组每组取几个的hasMany查询

表结构

商品分类 goods_category

id name
1 百货
2 家居

商品 goods

id goods_category_id name
1 1 牙刷
2 1 牙膏
3 1 牙线
4 2 凳子
5 2 桌子

以下SQL成立

select * from (
select * , row_number() over (partition by goods_category_id) as rn
) t where rn <= 2

可以实现:每个商品分类,分别取两条数据

现在model定义如下:

//商品分类
function goods() {
    return $this->hasMany('goods', 'goods_category_id','id');
}

在查询时,以分类查商品

$category = GoodsCategory::with(['goods' => fn($query) $query-???])

有好的方法吗。

还是只能直接从goods查,然后再循环按照分类ID重新拼成数组再输出了

《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 5

学到了.. zhuanlan.zhihu.com/p/484290987

我没啥好办法, 我只能想到直接从 goods 查。

1年前 评论
sanders

没找到现成的包哈,感觉上应该可以通过宏扩展 HasMany 来加入实现该查询的方法。置于为什么要用扩展的方式,我觉得因为 Relation::getKeysprotected 方法。

1年前 评论
sanders

具体方法我用我们的订单和订单商品模型打了个样,在tinker里面试了一下,应该是可以的:

Illuminate\Database\Eloquent\Relations\HasMany::macro('window', function(int $size) {
$queryOrigin = $this->selectRaw('*,row_number() over (partition by ' . $this->foreignKey . ') as rn');
$clone = clone $this;
$this->getBaseQuery()->wheres=[];
$this->getBaseQuery()->from='';
$this->getBaseQuery()->select('*')->fromSub($clone->getBaseQuery(), 't')->where('rn','<=',$size);
});
# 查询如下
App\Models\Order::with(['orderGoods'=>fn($query) => $query->window(2)])->limit(2)->get();

需要注意的是这里有些局限性,把所有字段都查出来了,但调整一下克隆的位置应该还比较好调整。自己用的话可以考虑放到 AppServiceProvider 里面。

1年前 评论
Imuyu 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!