Laravel9中如何将多对多关联Tag名称转为属性用于CSV导出
解决Laravel多对多关联中Tag名称逗号分隔导出的问题
方案一:使用Eloquent访问器(推荐)
在Portal模型中定义一个访问器,自动将关联的Tag名称拼接为逗号分隔的字符串:
// app/Models/Portal.php use Illuminate\Database\Eloquent\Casts\Attribute; class Portal extends Model { // 已有的多对多关联定义 public function tags() { return $this->belongsToMany(Tag::class, 'portal_tag'); } // 定义Tag名称拼接的访问器 protected function tagsNames(): Attribute { return Attribute::make( get: fn () => $this->tags->pluck('name')->join(','), ); } }
查询时通过append方法将该属性加入结果集:
$portals = Portal::with('tags') ->select('url','type','topic','description','prohibited','visits','facebook_url','twitter_url','instagram_url') ->where('user_id', Auth::id()) ->get() ->append('tags_names');
此时每个Portal实例都会带有tags_names字段,可直接用于CSV导出。
方案二:原生SQL查询(直接在select中获取)
如果希望直接通过数据库查询得到拼接后的字段,可使用GROUP_CONCAT结合关联查询:
use Illuminate\Support\Facades\DB; $portals = Portal::select([ 'portals.url', 'portals.type', 'portals.topic', 'portals.description', 'portals.prohibited', 'portals.visits', 'portals.facebook_url', 'portals.twitter_url', 'portals.instagram_url', DB::raw('GROUP_CONCAT(tags.name SEPARATOR ",") as tags_names') ]) ->join('portal_tag', 'portals.id', '=', 'portal_tag.portal_id') ->join('tags', 'portal_tag.tag_id', '=', 'tags.id') ->where('portals.user_id', Auth::id()) ->groupBy('portals.id') ->get();
注意:若使用SQLite数据库,需将GROUP_CONCAT(tags.name SEPARATOR ",")改为GROUP_CONCAT(tags.name, ',');若开启Laravel严格模式,需确保groupBy包含所有非聚合字段,否则可能触发SQL错误。
内容的提问来源于stack exchange,提问作者Don Don Don
相关产品推荐
相关产品推荐

