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

Laravel 5.5:嵌套查询与模型关联技术问询

解决Eloquent关联查询特定用户下符合条件的Shipment数据

嗨,我来帮你搞定这个查询需求!首先咱们得先确认模型之间的关联关系定义是正确的,这样后续的查询才能顺利跑起来。

第一步:确认模型关联定义

先把各个模型的关联方法写对,确保Eloquent能正确识别它们之间的关系:

User模型(User.php)

用户和运单是一对多关系,所以在User里定义shipments方法:

class User extends Model
{
    public function shipments()
    {
        return $this->hasMany(Shipment::class);
    }
}

Shipment模型(Shipment.php)

运单和状态历史是一对多关系,同时也可以通过hasManyThrough直接关联到Status(可选,但方便后续查询):

class Shipment extends Model
{
    // 反向关联用户(可选)
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    // 关联状态历史
    public function statusHistories()
    {
        return $this->hasMany(StatusHistory::class);
    }

    // 可选:通过状态历史关联状态
    public function statuses()
    {
        return $this->hasManyThrough(Status::class, StatusHistory::class);
    }
}

StatusHistory模型

状态历史属于运单和状态:

class StatusHistory extends Model
{
    public function shipment()
    {
        return $this->belongsTo(Shipment::class);
    }

    public function status()
    {
        return $this->belongsTo(Status::class);
    }
}

第二步:执行查询获取目标数据

接下来就可以通过whereHas方法来过滤符合条件的Shipment了——这个方法的作用是筛选出拥有满足特定条件的关联模型的主模型,正好符合你的需求。

场景1:筛选StatusHistory中包含特定Status ID的Shipment

假设你要找用户ID为$userId的所有运单,且这些运单的状态历史中存在状态ID为$targetStatusId的记录:

// 替换成你的目标用户ID和状态ID
$userId = 1;
$targetStatusId = 5;

$targetShipments = User::find($userId)->shipments()
    ->whereHas('statusHistories', function ($query) use ($targetStatusId) {
        // 指定状态历史的status_id等于目标值
        $query->where('status_id', $targetStatusId);
    })
    ->get();

场景2:筛选包含特定StatusHistory ID的Shipment

如果你的需求是找状态历史ID等于$targetHistoryId的运单(属于指定用户),只需要修改where条件即可:

$userId = 1;
$targetHistoryId = 10;

$targetShipments = User::find($userId)->shipments()
    ->whereHas('statusHistories', function ($query) use ($targetHistoryId) {
        $query->where('id', $targetHistoryId);
    })
    ->get();

另一种写法:从Shipment模型出发查询

如果你更习惯从Shipment模型开始查询,也可以这样写,效果完全一致:

$targetShipments = Shipment::whereHas('user', function ($query) use ($userId) {
        $query->where('id', $userId);
    })
    ->whereHas('statusHistories', function ($query) use ($targetStatusId) {
        $query->where('status_id', $targetStatusId);
    })
    ->get();

补充说明

  • 如果需要同时加载关联的StatusHistory或Status数据,可以在查询末尾加上with(['statusHistories', 'statuses']),避免N+1查询问题。
  • whereHas默认是匹配存在至少一条符合条件的关联记录,如果你需要所有关联记录都符合条件,可以用whereHas(..., true)或者whereEveryHas(Laravel 8.57+版本支持)。

内容的提问来源于stack exchange,提问作者Felipe Peña

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:15:57