我有一个具有以下模型的laravel应用程序
Location (hasOne: Device) : [id, device_id, lat, lng]
Device (hasMany: Location) : [id, name]
我需要获取给定设备的最新位置。假设我有一组设备ID。
[1, 2, 3]
我正在尝试制作一个API,该API应该为请求提供平坦的响应。显然,响应应如下所示。
[
{
"device_id": "1",
"name": "A",
"lat":"8.311",
"lng":"11.1111"
},
{
"device_id": "2",
"name": "B",
"lat":"8.1111",
"lng":"88.1111"
},
{
"device_id": "3",
"name": "C",
"lat":"5.1111",
"lng":"25.1111"
}
]
我尝试了许多方法来找到有效的解决方案以获得正确的答案。到目前为止,我能想到的最好的解决方案是使用Location
从device_id
表中直接获取最新位置。所以我尝试了这个。
Location::whereIn('device_id', [1, 2, 3])->get()
给出给定设备的所有位置条目。但是我只想要每个设备的最新位置条目。所以我尝试了这个。
Location::whereIn('device_id', [1, 2])->latest()->first()->get()
显然,每个设备都给我多个位置。我不确定该如何解决。
>>> Location::whereIn('device_id', [1, 2])->get()
=> Illuminate\Database\Eloquent\Collection {#2883
all: [
App\Location {#2895
id: 1,
device_id: 1,
lat: "39",
lng: "53",
extras: "JCRskRtaBJ",
delete_flag: 0,
created_at: "2018-07-25 12:11:21",
updated_at: "2018-07-25 12:11:21",
},
App\Location {#2903
id: 3,
device_id: 1,
lat: "73",
lng: "23",
extras: "0cOy8rne9S",
delete_flag: 0,
created_at: "2018-07-25 12:11:21",
updated_at: "2018-07-25 12:11:21",
},
App\Location {#2894
id: 5,
device_id: 2,
lat: "55",
lng: "28",
extras: "rT18VZxA7i",
delete_flag: 0,
created_at: "2018-07-25 12:11:21",
updated_at: "2018-07-25 12:11:21",
},
App\Location {#2885
id: 7,
device_id: 1,
lat: "58",
lng: "74",
extras: "TAbM4x53iH",
delete_flag: 0,
created_at: "2018-07-25 12:11:21",
updated_at: "2018-07-25 12:11:21",
},
App\Location {#2900
id: 8,
device_id: 1,
lat: "47",
lng: "7",
extras: "yhr4sbUs2R",
delete_flag: 0,
created_at: "2018-07-25 12:11:21",
updated_at: "2018-07-25 12:11:21",
},
App\Location {#2882
id: 9,
device_id: 2,
lat: "27",
lng: "60",
extras: "NqRPvaqosG",
delete_flag: 0,
created_at: "2018-07-25 12:11:21",
updated_at: "2018-07-25 12:11:21",
},
App\Location {#2915
id: 10,
device_id: 1,
lat: "35",
lng: "37",
extras: "6e7yHT4qP3",
delete_flag: 0,
created_at: "2018-07-25 12:11:21",
updated_at: "2018-07-25 12:11:21",
},
],
}
我正在寻找一个查询,该查询仅从location类返回lat
,lng
并将其附加为属性,以便获得平坦的json响应。反正有可能做到吗?
答案 0 :(得分:3)
您可以使用Eloquent: API Resources获得所需的内容:
首先在Device
模型中创建一个新关系,即使hasMany
是它们之间的真实关系,您也可以将hasOne
与latest()
一起使用以获取最后一个位置:
public function lastLocation()
{
return $this->hasOne('App\Location')->latest();
}
然后,您必须创建一个设备资源:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Device extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
return [
'device_id' => $this->id,
'name' => $this->name,
'lat' => $this->lastLocation->lat,
'lng' => $this->lastLocation->lng,
];
}
}
最后,您可以在控制器中执行以下操作:
use App\Device;
use App\Http\Resources\Device as DeviceResource;
function YourMethod() {
$devices = Device::with('lastLocation')
->whereIn([1, 2, 3])
->get();
return DeviceResource::collection($devices);
}
文档中提到的另一件事:
默认情况下,当 资源响应转换为JSON。因此,例如 资源收集响应如下所示:
{ "data": [ { "id": 1, "name": "Eladio Schroeder Sr.", "email": "therese28@example.com", }, { "id": 2, "name": "Liliana Mayert", "email": "evandervort@example.com", } ] }
要删除数据包装器:
如果您想禁用最外面的资源的包装, 您可以在基础资源类上使用noWrapping方法。 通常,您应该从AppServiceProvider调用此方法,或者 在向您的每个请求中加载的另一个服务提供商 应用程序:
public function boot() { Resource::withoutWrapping(); }
答案 1 :(得分:1)
关键是将file:
与groupBy
一起使用。然后仅将您想要的列传递给latest
。然后根据结果集返回响应,并根据结果返回状态码。
get