Laravel Eloquent中如何限定嵌套with查询的结果范围
解决嵌套预加载时过滤当前Fund的Participation问题
问题描述
我需要实现以下循环逻辑,遍历用户的基金、每个基金下的标签,以及该基金下对应标签的参与记录:
foreach($user->funds as $fund) { dump($fund->name); foreach($fund->tags as $tag) { dump('Tag: '.$tag->name); foreach($tag->participations as $participation) { // 当前拿到的是该标签下所有基金的参与记录,我需要的是当前循环的fund下、该标签对应的参与记录 dump('Participation: '.$participation->id.' User: '.$participation->user_id.' Fund: '.$participation->fund_id); } } }
当前查询语句中,我尝试给participations的查询添加fund_id过滤,但无法直接填入当前循环的fund_id;如果去掉这个where子句,遍历标签时会拿到所有基金的相关参与数据:
$user = User::where('id', $user_id) ->with(['funds' => function($query) use ($user_id) { $query->with(['tags' => function($query) use ($user_id) { $query->where('participations.user_id', $user_id) ->with(['participations' => function($query) use ($user_id) { $query->where('user_id', $user_id) ->where('fund_id', ?); // 无法直接获取当前fund的id }]); }]); }]) ->first();
模型结构:
- User:id
- Fund:id
- Tag:id
- Participation:id、fund_id、user_id、tag_id
解决方案
嵌套预加载是批量查询关联数据,无法直接获取单个fund的id,可通过whereColumn关联participations.fund_id与外层funds.id,确保每个标签只加载对应基金的参与记录:
$user = User::where('id', $user_id) ->with(['funds' => function($query) use ($user_id) { $query->with(['tags' => function($query) use ($user_id) { // 提前过滤出有当前用户参与记录的标签 $query->whereHas('participations', function($subQuery) use ($user_id) { $subQuery->where('user_id', $user_id); }) // 预加载参与记录,同时限制为当前基金下的数据 ->with(['participations' => function($subQuery) use ($user_id) { $subQuery->where('user_id', $user_id) ->whereColumn('participations.fund_id', 'funds.id'); }]); }]); }]) ->first();
原理说明
whereColumn('participations.fund_id', 'funds.id')让Laravel在查询参与记录时,自动关联外层funds表的id字段,确保只加载属于当前基金的参与记录。whereHas用于过滤掉无当前用户参与记录的标签,减少不必要的数据加载。
内容的提问来源于stack exchange,提问作者Michel FW
相关产品推荐
相关产品推荐

