【问题标题】:Laravel: Filter nested relationships?Laravel:过滤嵌套关系?
【发布时间】:2017-03-02 07:50:56
【问题描述】:

我不明白为什么这不起作用:

Device::with(['travel.move.position' => function($q) use ($start, $end) {
    return $q->whereBetween('created_date', [$start, $end]);
}]);

我认为它应该给我所有具有travel->move->position 关系的设备,但只有那些position.datetime 介于$start$end 之间的设备

我尝试了类似的东西

Device::whereHas('travel.move.position', function($q) use ($start, $end) {
    return $q->whereBetween('created_date', [$start, $end]);
});

我得到了预期的结果,但我没有得到渴望的关系。

为答案 1 添加了查询:

select * 
from `devices` 
where exists (
    select * from `travels` 
    inner join `travel_info` on `travel_info`.`id` = `travels`.`info_id` 
    where `devices`.`id` = `travel_info`.`device_id` 
    and exists (
        select * 
        from `moves` 
        where `moves`.`travel_id` = `travels`.`id` 
        and exists (
            select * from `positions` 
            where `moves`.`position_id` = `positions`.`id` and `created_at`
            between ? and ?
        )
    ) 

查询是完美的(就像 whereHas 一样)但是何时使用 with():

select `travels`.*, `travel_info`.`device_id` 
from `travels` 
inner join `travel_info` on `travel_info`.`id` = `travels`.`info_id` 
where `travel_info`.`device_id` in (?, ?, ?) 

.... 
select * from `moves` where `moves`.`travel_id` in (?, ..., ?)
....
select * from `positions` where `positions`.`id` in (?, ..., ?)

【问题讨论】:

  • 这段代码只过滤position,而不是device。因此,您仍将获得所有设备,但在每个设备->旅行->移动关系中,您只会看到与您的过滤器匹配的位置。
  • 你的领域真的叫datetime吗?由于这是 mysql 中的保留字:dev.mysql.com/doc/refman/5.7/en/keywords.html 我想你可能需要引用它whereBetween('datetime', [$start, $end]);
  • 尝试将with('travel.move.position') 添加到您的第二个查询中。然后它会为您提供预期的结果以及急切加载的关系。
  • @Cyclone 。不,它是一个西班牙语单词,意思相同,但我为了更好地理解而改变了。
  • @kanashin - haha​​ okej 然后我明白了 - 也许你应该把它改成其他的东西,比如 created_time 等 =)

标签: laravel relationship


【解决方案1】:

好的,经过与问题作者的长时间讨论,我们发现问题不在于查询本身,而在于 with() 语句中的关系加载不正确。

我想出了以下查询,它似乎返回了预期的结果。它首先执行一个主查询以获取所有符合过滤条件的设备,然后将相同的过滤器应用于我们需要预先加载的每个关系:

$start = '2016-10-01';
$end = '2016-10-31';

$devices = Device::whereHas('travel.move.position', function($q) use ($start, $end) {
    $q->whereBetween('created_at', [$start, $end]);
})->with([
    'travel' => function($q1) use ($start, $end) {
        $q1->whereHas('move.position', function($q2) use ($start, $end) {
            $q2->whereBetween('created_at', [$start, $end]);
        });
    },
    'travel.move' => function($q1) use ($start, $end) {
        $q1->whereHas('position', function($q2) use ($start, $end) {
            $q2->whereBetween('created_at', [$start, $end]);
        });
    },
    'travel.move.position' => function($q1) use ($start, $end) {
        $q1->whereBetween('created_at', [$start, $end]);
    }
])->get();

【讨论】:

  • 谢谢但还是一样:我得到一个设备->旅行->移动->位置->created_at == '2016-09-23'
  • 您能否打开数据库查询日志记录并检查上面代码的 SQL 查询并将其发布到您的问题中?
  • 一个招式可以多位吗?
  • 不,不能超过一个。这是一种归属关系
  • 您添加的 SQL 查询中有两处可疑之处: 1. where moves.position_id = positions.id and created_at ... 为什么 created_at 没有以它的表名作为前缀,例如positions.created_at? 2.select * from positions where positions.id in (?, ..., ?)不正确。应该是... positions.move_id in (?, ..., ?)
猜你喜欢
  • 2020-11-22
  • 1970-01-01
  • 2015-10-16
  • 2022-01-03
  • 2014-10-27
  • 2020-10-15
  • 1970-01-01
  • 2018-08-04
  • 2021-07-19
相关资源
最近更新 更多