Laravel如何在filter()后直接获取模型指定字段而非全量字段
Laravel 关联集合过滤并指定字段的优化方案
最优方式:数据库层面预加载时处理
别等拿到集合再折腾,直接在预加载关联的时候就完成过滤和字段限制,数据库层面处理比集合操作性能好太多,还省内存:
$filtered = MainModel::with(['relationA' => function ($query) { // 过滤掉名称为Lorem Ipsum的条目,同时只取需要的字段 // 注意必须包含关联外键(比如main_model_id,根据你的实际外键名调整),否则关联不上 $query->where('name', '!=', 'Lorem Ipsum') ->select('id', 'name', 'main_model_id'); }])->get()->map(fn (MainModel $mainModel) => [ 'id' => $mainModel->getRouteKey(), 'name' => $mainModel->name, 'relationAFiltered' => $mainModel->relationA, // 直接用预加载好的结果就行 ]);
集合层面的简化写法
如果一定要在集合里处理,Laravel没有直接把filter和指定字段合并的单一方法,但可以用更语义化的写法简化:
'relationAFiltered' => $mainModel->relationA // reject是filter的反向,这里用它更贴合“排除某条”的语义 ->reject(fn(SomeModel $someModel) => $someModel->name === 'Lorem Ipsum') ->map(fn($item) => $item->only(['id', 'name'])),
要是你经常需要这种操作,还可以给集合加个自定义宏,封装成一步:
// 在AppServiceProvider的boot方法里注册宏 use Illuminate\Support\Collection; Collection::macro('filterAndOnly', function ($filterCallback, $fields) { return $this->filter($filterCallback)->map(fn($item) => $item->only($fields)); }); // 之后用起来就很简洁 'relationAFiltered' => $mainModel->relationA->filterAndOnly( fn(SomeModel $someModel) => $someModel->name !== 'Lorem Ipsum', ['id', 'name'] ),
总结
优先用预加载时的数据库过滤,性能最佳;集合操作的话,reject+map+only已经足够简洁,自定义宏适合复用场景。
内容的提问来源于stack exchange,提问作者MartinTTS
相关产品推荐
相关产品推荐

