Laravel多对多关联重复问题:如何将pivot表role_id聚合为数组
Laravel多对多关联聚合pivot角色ID解决方案
你可以选择以下两种方案实现需求:
方案1:集合后置处理(实现最简单,适合中小数据量)
不需要修改原有关联定义,在查询出结果后通过Laravel集合方法分组聚合即可:
// 查询指定作者的作品并处理 $author = Author::find($yourAuthorId); $writings = $author->writings // 按作品ID分组 ->groupBy('id') ->map(function ($itemGroup) { // 取第一个作品作为基础数据 $writing = $itemGroup->first(); // 聚合该作品下所有角色ID $writing->pivot->role_id = $itemGroup->pluck('pivot.role_id')->unique()->values()->toArray(); return $writing; }) // 重置集合索引 ->values();
返回的$writings就已经是每个作品仅一条、pivot的role_id为数组的结构,直接序列化输出即可得到你想要的JSON格式。
方案2:查询层聚合(性能更优,适合大数据量场景)
直接在关联查询时通过SQL聚合函数合并角色ID,减少查询返回的数据量:
第一步:修改关联定义
public function writings(){ return $this->belongsToMany(Writing::class, 'author_writing', 'author_id', 'writing_id') ->selectRaw('writings.*, GROUP_CONCAT(author_writing.role_id) as aggregate_role_ids') // 按作品ID分组去重 ->groupBy('writings.id') ->withPivot(['writing_id', 'author_id']); }
注:如果使用PostgreSQL数据库,将
GROUP_CONCAT替换为STRING_AGG(author_writing.role_id, ',')即可。
第二步:格式化输出
$author = Author::find($yourAuthorId); $writings = $author->writings->map(function ($writing) { // 将聚合的字符串拆分为数组 $writing->pivot->role_id = explode(',', $writing->aggregate_role_ids); // 清理临时聚合字段 unset($writing->aggregate_role_ids); return $writing; });
可选优化:API资源类统一格式化
如果是接口返回场景,你可以创建Laravel资源类统一处理输出结构,避免每次查询都重复写处理逻辑。
内容的提问来源于stack exchange,提问作者sosomethin
相关产品推荐
相关产品推荐

