首页 > 解决方案 > 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. 使用 Child 获取所有 Parent 数据
  2. 仅在按 start_date 降序排序后获取第一个孩子
  3. 根据结果​​ 2 使用子 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,
          "star_date" : "2021-03-01"
       },
       {
          "id" : 4,
          "star_date" : "2021-03-20"
       }
    ]
  }
]

步骤 2 的结果(按 start_date 降序排列)

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

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

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

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

任何人都可以帮助我实现我想要做的事情。

标签: phplaraveleloquentrelation

解决方案


你想要做的是使用 subquery :

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();


推荐阅读