Laravel 根据第一行子行过滤父行

问题描述

我正在尝试此代码

$query = Parent::where('state',1)
         ->with(array('child'=> function ($q) use ($end_date) {
             $q->where('start_date','<=',$end_date);
         }));

$query->whereHas("child",function ($query) use ($filter) {
            if (isset($filter["id"]) && $filter["id"] != "") {
                $query->where("id",'=',$filter["id"]);
            }
        });

然后在父模型我有这个代码

public function child()
{
        return $this->hasOne('App\Models\Child','code','code');
}

我想做这样的事情:

  1. 获取所有父数据和子数据
  2. 仅按 start_date 降序获取 order 之后的第一个孩子
  3. 根据结果 2 使用 Child id 过滤父数据

json 示例:

第 1 步的结果

"parent" : [
  {
    "id": 1,"code": "ABC"
    "child" : [
       {
          "id" : 1,"star_date" : "2021-03-01"
       },{
          "id" : 2,"star_date" : "2021-03-15"
       }
    ]
  },{
    "id": 2,"code": "XYZ"
    "child" : [
       {
          "id" : 3,{
          "id" : 4,"star_date" : "2021-03-20"
       }
    ]
  }
]

第 2 步的结果(按开始日期降序排列)

"parent" : [
  {
    "id": 1,"code": "ABC"
    "child" : 
       {
          "id" : 2,"star_date" : "2021-03-15"
       }
  },"code": "XYZ"
    "child" : 
       {
          "id" : 4,"star_date" : "2021-03-20"
       }
  }
]

第 3 步的结果(按孩子 ID = 2 过滤)

"parent" : [
  {
    "id": 1,"star_date" : "2021-03-15"
       }
  }
]

但是我无法得到我想要的结果..

谁能帮助我实现我想要做的事情。

解决方法

你想要做的是使用子查询:

public function lastChild()
    {
        return $this->belongsTo(Child::class,'last_child_id');
    }

    public function scopeWithLastChild($query)
    {
        $query->addSelect([
                'last_child_id' => $this->lastChildSubQuery(),]
        )->with('lastChild');
    }

    public function lastChildSubQuery($select_field = 'id')
    {
        return Child::selectRaw($select_field)
                       ->whereColumn('parents.code','childs.code')
                       ->orderByDesc('start_date')
                       ->limit(1);
    }

然后你可以像这样得到你的 lastChild :

$parent = Parent::withLastChild()->first();
$parent->lastChild->[...];

现在,如果您想根据最后一个孩子的“id”列过滤您的父母:

$parent = Parent::withLastChild()
->having('last_child_id',$filter['id'])
->first();

如果你想要任何其他列:

Parent::select()
        ->addSelect([
                'last_child_foo' => $this->lastChildSubQuery('foo'),]
        )->having('last_child_foo',$filter['foo'])
         ->first();