【问题标题】:Laravel Get previous records by date (optimization)Laravel 按日期获取以前的记录(优化)
【发布时间】:2020-08-12 02:43:03
【问题描述】:

我有一个带有字段的预订表:

  • 姓名 |字符串
  • 来自 |日期时间
  • 到 |日期时间

我选择其中一些预订并将它们显示为列表。我还会检查之前的预订是否相隔不到 30 天。

我通过查询每个预订的前一个预订来做到这一点:

@if ($booking->previousBooking()) // Simplified version but you get the idea

底层代码:

public function previousBooking()
    {
        return Booking::where('from', '<', $this->from)
            ->orderByDesc('from')
            ->first();
    }

您可能已经猜到了:它为每个预订添加了一个查询。

最好的情况是急切地加载“以前的预订”(with),这样就可以像这样访问它:

$booking->previous_booking->from

有没有办法做到这一点?

约束:

  • 我无法查询所有预订,按“from”排序,然后只获取上一个索引

【问题讨论】:

    标签: laravel eloquent laravel-6 eager-loading


    【解决方案1】:

    看看 Jonathan Reinink 的 this article。您可以通过在您的 Booking 模型上模拟 previous_booking_id 来应用他的解决方案。然后添加previousBooking() 关系并使用with('previousBooking') 查询。如果您在实施方面需要任何帮助,请告诉我。

    更新


    将以下范围添加到您的 Booking 模型:

    public function previousBooking()
    {
        return $this->belongsTo(Booking::class);
    }
    
    public function scopeWithPreviousBooking($query)
    {
        $query->addSelect(['previous_booking_id' => Booking::select('id')
            ->whereColumn('previous_booking.from', '<', 'bookings.to')
            ->orderByDesc('from')
            ->take(1)
        ])->with('previousBooking');
    }
    

    您现在可以使用以下方式获取所有包含之前预订 ID 的预订:

    $bookings = Booking::withPreviousBooking()->get();
    

    现在所有预订都应该有一个previous_booking_id。我们将with('previousBooking') 添加到范围的末尾,就像我们查询预订的关系一样。 Eloquent 不关心 previous_booking_id 是否在数据库中,只要它在模型中可用(我们已经通过 addSelect() 方法完成)。

    您现在应该可以在视图中使用您请求的解决方案了:

    $booking->previousBooking->from
    

    注意:如果您已应用范围,则只能访问previousBooking 关系。如果没有,previous_booking_id 不可用,因此关系将为空。如果您总是想加载以前的预订,请考虑将其添加为global scope。但是,我建议只在需要的地方应用范围。

    【讨论】:

    • 你将如何模拟previous_booking_id?
    • 我已经更新了我的答案。这应该很适合你!这是我所知道的最优化的解决方案。
    • 好吧,我已经做到了(添加了 return $this->belongsTo(Booking::class, 'previous_booking_id');)。但是现在我每次预订都得到相同的先前预订(相同的 ID)。你知道那可能是从哪里来的吗?
    • 问题出在子查询中。 “从”是一个日期吗?你能确保记录不都是一样的吗?尝试重写子查询以确保选择正确的先前预订
    • 是的,找到了。我需要像这样更改表名: DB::table('Bookings AS previous_booking')->select('previous_booking.id')
    猜你喜欢
    • 2020-12-16
    • 1970-01-01
    • 2021-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-03
    • 1970-01-01
    相关资源
    最近更新 更多