You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中Timeline模型基于时间的前后活动关联实现问询

实现方案

1. 自关联定义(基于时间戳筛选)

在你的Timeline模型中添加两个自关联方法,分别用于获取下一个活动和上一个活动:

// 获取下一个活动(取start时间大于当前的最小记录)
public function nextTimeline()
{
    return $this->hasOne(Timeline::class)
        ->ofMany(
            [
                'start' => 'min', // 优先筛选比当前start大的最早记录
                'id' => 'min'     // 若start时间重复,取id最小的避免结果歧义
            ],
            function ($query) {
                $query->where('start', '>', $this->start);
            }
        );
}

// 获取上一个活动(取start时间小于当前的最大记录)
public function previousTimeline()
{
    return $this->hasOne(Timeline::class)
        ->ofMany(
            [
                'start' => 'max', // 优先筛选比当前start小的最晚记录
                'id' => 'max'     // 若start时间重复,取id最大的避免结果歧义
            ],
            function ($query) {
                $query->where('start', '<', $this->start);
            }
        );
}

2. 预加载关联数据

直接使用Laravel的预加载方法即可,不会产生N+1查询问题:

// 预加载单条Timeline的前后活动
$timeline = Timeline::with(['nextTimeline', 'previousTimeline'])->find($id);

// 预加载多条Timeline的前后活动
$timelines = Timeline::with(['nextTimeline', 'previousTimeline'])->get();

关键说明

  • 无需将id同时设为foreignKey和localKey:这里的关联不是基于外键的父子关系,而是通过时间条件筛选同表内的其他记录,因此不需要指定外键参数。
  • ofMany()的作用:Laravel的ofMany()专门用于处理一对多关系中取唯一记录的场景,这里用它指定排序规则(取最小/最大的start时间),结合闭包过滤出符合时间范围的记录。
  • 重复时间处理:添加id作为次要排序字段,避免多个活动拥有相同start时间时出现结果不确定的情况。

备选方案(自定义子查询)

如果需要更灵活的控制,可以用子查询直接在查询构造器中获取前后活动的ID,再关联:

$timelines = Timeline::addSelect([
    'next_timeline_id' => Timeline::select('id')
        ->where('start', '>', DB::raw('timelines.start'))
        ->orderBy('start', 'asc')
        ->orderBy('id', 'asc')
        ->limit(1),
    'previous_timeline_id' => Timeline::select('id')
        ->where('start', '<', DB::raw('timelines.start'))
        ->orderBy('start', 'desc')
        ->orderBy('id', 'desc')
        ->limit(1)
])->with(['nextTimeline' => function ($query) {
    $query->select('id', 'start', 'end', '其他需要的字段'); // 按需指定字段减少查询开销
}, 'previousTimeline'])->get();

这种方式同样支持预加载,且可以更精准地控制查询字段和条件。

内容的提问来源于stack exchange,提问作者wivku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 04:00:05