Laravel中如何筛选多对多关系里最新状态为sold的Phone记录
筛选最新状态为“sold”的Phone记录(Laravel关联场景)
嘿,我来帮你搞定这个筛选和格式化的问题!先理清楚你的场景:虽然Phone和PhoneStatus是多对多关系,但你在Phone模型里通过hasOne+latest()的方式拿到了每个Phone的最新状态,现在要筛选出这些最新状态是sold的Phone,还要返回指定的结构。
问题回顾
场景说明:Phone与PhoneStatus为多对多关系(Phone拥有多个PhoneStatus,PhoneStatus属于多个Phone)。已在Phone模型中定义关联以获取最新状态:
public function phoneStatus(){ return $this->hasOne(PhoneStatus::class, 'phone_id','id')->latest(); }现需筛选所有最新状态为“sold”的Phone记录,期望返回格式:
[ { "id": 1, "name": "iphone XYZ", "phonestatus": { "phone_status": "sold" } } ]当前控制器代码为:
$getProjectData = Phone::whereHas...请补充完整实现逻辑。
完整实现代码
直接给你补全并优化后的控制器代码,同时处理了数据格式化:
$getProjectData = Phone::whereHas('phoneStatus', function ($query) { // 筛选关联的最新状态为sold的记录 $query->where('phone_status', 'sold'); }) ->with('phoneStatus') // 预加载关联,避免N+1查询问题 ->get() ->map(function ($phone) { // 把Eloquent模型转换成你要的数组结构 return [ 'id' => $phone->id, 'name' => $phone->name, 'phonestatus' => [ 'phone_status' => $phone->phoneStatus->phone_status ] ]; });
关键细节解释
whereHas的作用:这里直接用你定义的phoneStatus关联来筛选,因为这个关联本身已经是取每个Phone的最新状态了,所以闭包里的条件只会匹配最新状态为sold的Phone,而不是所有状态里出现过sold的Phone。with('phoneStatus')的必要性:预加载关联数据,不然在map里遍历每个Phone时,会为每个Phone单独查一次PhoneStatus,造成不必要的数据库开销(N+1性能问题)。map方法格式化:把Laravel返回的Eloquent集合转换成你期望的嵌套数组结构,确保字段名和层级完全符合需求。
小提示
如果你的PhoneStatus表不是用created_at来判断“最新”的,可以在模型的关联方法里指定排序字段,比如改成latest('updated_at')或者自定义的时间字段,保证拿到的确实是最新的状态记录。
内容的提问来源于stack exchange,提问作者Ander
相关产品推荐
相关产品推荐

