Laravel - 过滤 morphOne 或 hasOne 关系

Laravel - Filter morphOne or hasOne relationship

我有三个通过 morph 关系关联的模型。

Shipment 可以有多个 Status 个实例,通过一个 StatusHistory class。

    class Status extends Model {
       //id, name
    }

    class Shipment extends Model {
       public function latestStatus() {
          return $this->morphOne('App\StatusHistory', 'model')->latest();
       }
    }

    class StatusHistory extends Model {
       public function model() {
            return $this->morphTo();
        }

        public function status() {
           return $this->belongsTo('App\Status', 'status_id');
        }
    }

我想获取所有 Shipment 个实体,其中 latestStatus 具有特定的 Status 名称值。

   Shipment::whereHas('latestStatus', function($query) {
      return $query->whereHas('status', function($query) {
         return $query->where('name', 'reserved');
      });
   })->get();

这不起作用,return 状态为 'reserved' 的所有实体,即使 latestStatus 可以是其他状态。

有什么想法吗?

编辑(添加样本信息):

我有 2 批货物。

  1. 第一个只有一个状态名称中包含 'reserved' 的状态历史实例。
  2. 第二个有两个状态历史实例,其状态名称为 'reserved' 和 'shipped'。 'shipped' 的状态历史记录实例创建时间晚于 'reserver'。

所以:

  1. 第一批货物的最后状态为 'reserved'。
  2. 第二批货物的最后状态为 'shipped'。

电话应该只return第一批出货。

最简单的解决方案是获取所有货件并在之后过滤它们:

Shipment::with('latestStatus.status')->get()->where('latestStatus.status.name', 'reserved')

根据您的数据库大小,这可能不是很有效。

只获取相关货件的查询:

Shipment::select('shipments.*')
    ->join('status_histories as sh', 'shipments.id', 'sh.model_id')
    ->join('statuses as st', 'sh.status_id', 'st.id')
    ->where('model_type', Shipment::class)
    ->where('st.name', 'reserved')
    ->where('created_at', function($query) {
        $query->selectRaw('MAX(created_at)')
            ->from('status_histories')
            ->where('model_id', DB::raw('sh.model_id'))
            ->where('model_type', DB::raw('sh.model_type'));
    })->get();