Laravel搜索功能优化:隐藏skill为空的Worker数据及JSON空字段
解决Laravel搜索中Skill为空数组的Worker不显示问题
我来帮你搞定这个问题!你现在遇到的核心问题是:whereHas('skill')只是检查Worker是否存在任意Skill关联,但你在with里又过滤了特定sub_skill_id的Skill,导致有些Worker虽然有其他Skill,但没有匹配你要找的sub_skill_id,所以返回的Skill数组是空的,但Worker本身还是被查出来了。
解决方案:同步whereHas和with的过滤条件
要让只有包含匹配sub_skill_id的Skill的Worker才被返回,你需要把whereHas的闭包条件和with里的保持一致,这样就能确保查询出来的Worker一定有符合条件的Skill,不会出现Skill为空数组的情况。
修改后的控制器代码如下:
$subSkillId = $request->input('sub_skill_id'); $workers = Worker::with(['skill' => function($query) use ($subSkillId) { $query->where('worker_skills.sub_skill_id', $subSkillId); }]) ->whereHas('skill', function($query) use ($subSkillId) { $query->where('worker_skills.sub_skill_id', $subSkillId); }) ->get();
如果你的Laravel版本支持短闭包(Laravel 8+),可以简化成更简洁的写法:
$subSkillId = $request->input('sub_skill_id'); $workers = Worker::with(['skill' => fn($q) => $q->where('sub_skill_id', $subSkillId)]) ->whereHas('skill', fn($q) => $q->where('sub_skill_id', $subSkillId)) ->get();
这样修改后,只有那些拥有匹配sub_skill_id的Skill的Worker才会被查询出来,它们的skill字段也会正确加载对应的关联数据,不会出现空数组的情况。
额外问题:如何在JSON中隐藏空字段
如果在其他场景下,你需要隐藏模型中空的关联字段或属性,可以用以下几种方法:
1. 使用模型的$hidden属性(全局隐藏)
在Worker模型中定义$hidden数组,指定默认要隐藏的字段:
class Worker extends Model { protected $hidden = ['skill']; // 默认隐藏skill字段 }
不过这种方法是全局的,如果你需要动态控制,推荐下面的方法。
2. 使用makeHidden()方法(动态隐藏)
在查询结果后,动态隐藏空的字段:
$workers = $workers->map(function($worker) { if ($worker->skill->isEmpty()) { $worker->makeHidden('skill'); } return $worker; });
3. 使用API资源(推荐用于API场景)
创建一个WorkerResource类,在资源里控制返回的字段:
namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class WorkerResource extends JsonResource { public function toArray($request) { $data = [ 'id' => $this->id, // 其他Worker字段... ]; // 只有当skill非空时才添加到返回数据中 if (!$this->skill->isEmpty()) { $data['skill'] = $this->skill; } return $data; } }
然后在控制器中返回资源集合:
return WorkerResource::collection($workers);
这样就能灵活控制JSON返回的字段,空的关联字段不会出现在响应中。
内容的提问来源于stack exchange,提问作者Nasihun Amin Suhardiyan
相关产品推荐
相关产品推荐

