Laravel Eloquent:按条件获取关联竞赛,无有效项则返回null
Laravel 关联模型筛选并处理空关联字段
我有一个Language模型集合,每个Language关联多个Competition模型。需求是:为每个Language获取endAt时间晚于或等于当前时间的有效竞赛;若不存在有效竞赛,则对应competitions字段设为null。
初始查询代码
$languages = $this->language->with('competitions')->get();
初始集合结果
[ [ 'name' => 'english', 'competitions' => [ [ 'endAt' => '...' ], [ 'endAt' => '...' ], ], ], [ 'name' => 'indonesian', 'competitions' => [ [ 'endAt' => '...' ], [ 'endAt' => '...' ], ], ] ];
期望结果
[ [ 'name' => 'english', 'competitions' => null, ], [ 'name' => 'indonesian', 'competitions' => [ 'endAt' => '...' ], ] ];
尝试的无效代码
$languages = $this->language->whereHas('competitions', function (Builder $query) { $query->whereDate('endAt', '>=', Carbon::now()); })->get();
解决方案
你之前用whereHas的问题是,它会直接过滤掉没有符合条件竞赛的Language,而我们需要保留所有Language,只是处理关联字段。可以分两步实现需求:
- 用
with的闭包筛选出每个Language下的有效竞赛 - 遍历集合,把空的竞赛数组转为
null
代码实现:
use Illuminate\Database\Eloquent\Builder; use Carbon\Carbon; // 第一步:筛选有效竞赛 $languages = $this->language->with(['competitions' => function (Builder $query) { $query->whereDate('endAt', '>=', Carbon::now()); }])->get(); // 第二步:处理空关联为null $languages = $languages->map(function ($language) { $language->competitions = $language->competitions->isEmpty() ? null : $language->competitions; return $language; });
也可以合并为链式调用,更简洁:
$languages = $this->language ->with(['competitions' => fn(Builder $query) => $query->whereDate('endAt', '>=', Carbon::now())]) ->get() ->map(fn($language) => tap($language, fn($lang) => $lang->competitions = $lang->competitions->isEmpty() ? null : $lang->competitions));
这样就能得到你想要的结果:所有Language都被保留,有有效竞赛的显示对应列表,没有的则competitions字段设为null。
内容的提问来源于stack exchange,提问作者R.M. Reza
相关产品推荐
相关产品推荐

