You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
            ]
        ];
    });

关键细节解释

  1. whereHas的作用:这里直接用你定义的phoneStatus关联来筛选,因为这个关联本身已经是取每个Phone的最新状态了,所以闭包里的条件只会匹配最新状态为sold的Phone,而不是所有状态里出现过sold的Phone。
  2. with('phoneStatus')的必要性:预加载关联数据,不然在map里遍历每个Phone时,会为每个Phone单独查一次PhoneStatus,造成不必要的数据库开销(N+1性能问题)。
  3. map方法格式化:把Laravel返回的Eloquent集合转换成你期望的嵌套数组结构,确保字段名和层级完全符合需求。

小提示

如果你的PhoneStatus表不是用created_at来判断“最新”的,可以在模型的关联方法里指定排序字段,比如改成latest('updated_at')或者自定义的时间字段,保证拿到的确实是最新的状态记录。

内容的提问来源于stack exchange,提问作者Ander

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:37:17