如何从 eloquent 中的 belongsToMany 关系中获取特定列的最小值
How to get min value of specific column from belongsToMany relationship in eloquent
我在 projects-devices tables 之间有多对多关系。我想 从每个项目的 设备 table 中获取特定列(电池电量) 的最小值。
我只用一个 sql 命令就可以成功。但是我怎样才能用有效的 eloquent 做到这一点呢?谢谢。
第一 table:项目
-- 编号
-- 名字
-- .
-- .
-- .
第二 table:设备
-- 编号
-- battery_level
-- .
-- .
-- .
第三个枢轴table:device_project
-- device_id
-- project_id
原始 sql:
如我所愿,效果很好,但我想用 eloquent 来做。
$projects = DB::select( DB::raw("select
`projects`.`id`, `projects`.`name`,
(select
`battery_level`
from `devices`
inner join `device_project`
on `devices`.`id` = `device_project`.`device_id`
where `projects`.`id` = `device_project`.`project_id`
order by `battery_level`
limit 1
) as `lowest_battery_level`
from `projects`"));
foreach ($projects as $project) {
$values[] = $project->lowest_battery_level
}
与eloquent:
这个问题:它会发送两个单独的 sql 查询,尽管我可以通过使用原始 sql 只用 1 个查询来做到这一点。它还从数据库中获取所有设备的电池电量。但是每个项目我只需要最低的一个。
$projects = Project::with('devices:battery_level')->get();
foreach ($projects as $project) {
$values[] = $project->devices->min('battery_level')
}
在您的项目模型中定义这样的关系
public function devices()
{
return $this->belongToMany(Device::class);
}
并在您的设备模型中定义这样的关系
public function projects()
{
return $this->belongToMany(Project::class);
}
然后在你的控制器中获取项目
$values = [];
$project = Project::find(1); //write your own custom code for gettign the projects
foreach($project->devices as $device)
$values[] = $device->battery_level;
dd($values);
经过多次尝试,我找到了答案。希望这也能帮助到其他人。
addSelect 方法帮助了我,我的 eloquent 代码现在更有效了。这只会创建一个查询,而不会像我想要的那样创建有关设备的详细(不必要的)信息。它仅提供每个项目的最低电池电量。
Eloquent 代码:
$projects = Project::select('projects.id', 'projects.name')
->addSelect([
'lowest_battery_level' => Device::select('battery_level')
->leftJoin('device_project', 'device_project.device_id', '=', 'devices.id')
->whereColumn('device_project.project_id', 'projects.id')
->orderBy('battery_level', 'asc') // no need asc if you wanna get lowest value first
->limit(1)
])
->get();
// can use like this
foreach ($projects as $project) {
$values[] = $project->lowest_battery_level
}
这将创建如下 sql 查询:
仅创建 1 个查询并仅获取项目结果而没有其他设备的详细信息。
select
`projects`.`id`,
`projects`.`name`,
(
select
`battery_level`
from `devices`
inner join `device_project` on `devices`.`id` = `device_project`.`device_id`
where `projects`.`id` = `device_project`.`project_id`
order by `battery_level`
limit 1
) as `lowest_battery_level`
from `projects`
与 Laravel Debugbar
的性能比较
数据库中有 100 个项目 和 1000 个设备。每个项目与 0-50 台设备有随机关系。不同的项目也可以与相同的设备有关系(多对多关系)。
与之前的eloquent代码:
$projects = Project::with('devices:battery_level')->get();
foreach ($projects as $project) {
$values[] = $project->devices->min('battery_level')
}
As it can be seen below, it uses 18 MB RAM and took 539 ms.
Creates 2783 Device objects and 100 Project objects
使用新的 eloquent 代码:(我在上面显示)
As it can be seen below, it uses 10 MB RAM and took 432 ms.
Creates no Device objects and only 100 Project objects
我在 projects-devices tables 之间有多对多关系。我想 从每个项目的 设备 table 中获取特定列(电池电量) 的最小值。
我只用一个 sql 命令就可以成功。但是我怎样才能用有效的 eloquent 做到这一点呢?谢谢。
第一 table:项目
-- 编号
-- 名字
-- .
-- .
-- .
第二 table:设备
-- 编号
-- battery_level
-- .
-- .
-- .
第三个枢轴table:device_project
-- device_id
-- project_id
原始 sql:
如我所愿,效果很好,但我想用 eloquent 来做。
$projects = DB::select( DB::raw("select
`projects`.`id`, `projects`.`name`,
(select
`battery_level`
from `devices`
inner join `device_project`
on `devices`.`id` = `device_project`.`device_id`
where `projects`.`id` = `device_project`.`project_id`
order by `battery_level`
limit 1
) as `lowest_battery_level`
from `projects`"));
foreach ($projects as $project) {
$values[] = $project->lowest_battery_level
}
与eloquent:
这个问题:它会发送两个单独的 sql 查询,尽管我可以通过使用原始 sql 只用 1 个查询来做到这一点。它还从数据库中获取所有设备的电池电量。但是每个项目我只需要最低的一个。
$projects = Project::with('devices:battery_level')->get();
foreach ($projects as $project) {
$values[] = $project->devices->min('battery_level')
}
在您的项目模型中定义这样的关系
public function devices()
{
return $this->belongToMany(Device::class);
}
并在您的设备模型中定义这样的关系
public function projects()
{
return $this->belongToMany(Project::class);
}
然后在你的控制器中获取项目
$values = [];
$project = Project::find(1); //write your own custom code for gettign the projects
foreach($project->devices as $device)
$values[] = $device->battery_level;
dd($values);
经过多次尝试,我找到了答案。希望这也能帮助到其他人。
addSelect 方法帮助了我,我的 eloquent 代码现在更有效了。这只会创建一个查询,而不会像我想要的那样创建有关设备的详细(不必要的)信息。它仅提供每个项目的最低电池电量。
Eloquent 代码:
$projects = Project::select('projects.id', 'projects.name')
->addSelect([
'lowest_battery_level' => Device::select('battery_level')
->leftJoin('device_project', 'device_project.device_id', '=', 'devices.id')
->whereColumn('device_project.project_id', 'projects.id')
->orderBy('battery_level', 'asc') // no need asc if you wanna get lowest value first
->limit(1)
])
->get();
// can use like this
foreach ($projects as $project) {
$values[] = $project->lowest_battery_level
}
这将创建如下 sql 查询:
仅创建 1 个查询并仅获取项目结果而没有其他设备的详细信息。
select
`projects`.`id`,
`projects`.`name`,
(
select
`battery_level`
from `devices`
inner join `device_project` on `devices`.`id` = `device_project`.`device_id`
where `projects`.`id` = `device_project`.`project_id`
order by `battery_level`
limit 1
) as `lowest_battery_level`
from `projects`
与 Laravel Debugbar
的性能比较数据库中有 100 个项目 和 1000 个设备。每个项目与 0-50 台设备有随机关系。不同的项目也可以与相同的设备有关系(多对多关系)。
与之前的eloquent代码:
$projects = Project::with('devices:battery_level')->get();
foreach ($projects as $project) {
$values[] = $project->devices->min('battery_level')
}
As it can be seen below, it uses 18 MB RAM and took 539 ms.
Creates 2783 Device objects and 100 Project objects
使用新的 eloquent 代码:(我在上面显示)
As it can be seen below, it uses 10 MB RAM and took 432 ms.
Creates no Device objects and only 100 Project objects