如何在Laravel Eloquent中从嵌套关联获取单条指定行数据?
问题描述
我有三个一对多关联的模型:Client拥有多个Point,Point拥有多个OrderPower。order_powers表包含value和date_from字段,date_from是该订购功率值生效的起始日期。
模型代码
Client 模型
public function points() { return $this->hasMany(Point::class); } public function order_powers() { return $this->hasManyThrough(OrderPower::class, Point::class); }
Point 模型
public function clients() { return $this->belongsTo(Client::class); } public function order_powers() { return $this->hasMany(OrderPower::class); }
OrderPower 模型
注:原代码方法名有误,已修正为正确的关联名称
public function point() { return $this->belongsTo(Point::class); }
需求
在单页中展示:
- 单个
Client的数据 - 该
Client所属的Point的数据 - 每个
Point对应的订购功率,仅显示date_from最新的一条数据的value值
当前问题
我使用Inertia和Vue的ClientController渲染代码如下,目前前两点已实现,但第三点存在问题:当前控制器会返回每个Point的所有order_powers,尝试用first()或take(1)会导致所有Point只显示同一条order_power,而非每个Point自身最新的那条。
当前控制器代码
return Inertia::render('Clientshow', [ 'client' => [ 'id' => $client->id, 'name' => $client->name, 'street' => $client->street, 'city' => $client->city, 'points' => $client->points()->with(['order_powers'=>function ($q) { $q->orderBy('date_from','desc'); } ])->get(), ], ]);
示例场景
- 一个
Client有两个Point - 每个
Point有两个OrderPower - Vue中每个
Point会显示两个值,我只想显示每个Point自己最新的那一个
Vue组件数据结构
>client:Reactive id:33 name:"ClientName" street:"StreetName" city:"CityName" >points:Array[2] >0:Object client_id:33 created_at:"2022-10-13T15:31:37.000000Z" id:65 >order_powers:Array[2] <- 我只想显示其中一个对象的value字段值 >0:Object >1:Object pp_type:"xxxx" updated_at:"2022-10-13T15:31:37.000000Z" >1:Object
解决方案
方法一:在Point模型新增关联(推荐)
在Point模型中添加一个关联,直接指向该Point最新的OrderPower:
public function latest_order_power() { return $this->hasOne(OrderPower::class)->latest('date_from'); }
然后修改控制器中的关联加载逻辑:
return Inertia::render('Clientshow', [ 'client' => [ 'id' => $client->id, 'name' => $client->name, 'street' => $client->street, 'city' => $client->city, 'points' => $client->points()->with('latest_order_power')->get(), ], ]);
Vue中直接调用该关联的value字段即可:
<div v-for="point in client.points" :key="point.id"> <p>最新订购功率:{{ point.latest_order_power?.value }}</p> </div>
方法二:查询时通过子查询获取最新值
如果不想新增关联,可以在查询Point时,用子查询直接取出最新的value:
return Inertia::render('Clientshow', [ 'client' => [ 'id' => $client->id, 'name' => $client->name, 'street' => $client->street, 'city' => $client->city, 'points' => $client->points() ->selectRaw('points.*, (SELECT value FROM order_powers WHERE order_powers.point_id = points.id ORDER BY date_from DESC LIMIT 1) AS latest_order_power_value') ->get(), ], ]);
Vue中直接使用新增的字段:
<div v-for="point in client.points" :key="point.id"> <p>最新订购功率:{{ point.latest_order_power_value }}</p> </div>
方法三:Vue端处理(备选)
如果后端不想修改,可利用后端已按date_from倒序排序的特性,在Vue中取数组第一个元素:
<div v-for="point in client.points" :key="point.id"> <p>最新订购功率:{{ point.order_powers[0]?.value }}</p> </div>
注:使用可选链
?.避免数组为空时出现报错
内容的提问来源于stack exchange,提问作者sunnyluk
相关产品推荐
相关产品推荐

