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

Laravel 11中如何限制hasMany关联仅获取最后1条数据?

Laravel 11 关联模型获取单条最新记录及时间过滤实现方案

问题背景

在Laravel 11 / MySQL 8环境下,Currency模型定义了如下关联方法用于关联CurrencyHistory表:

public function latestCurrencyHistory(): HasMany
{
    return $this->hasMany(CurrencyHistory::class)->latest();
}

执行预加载查询时:

$this->currencies = Currency
    ::getByActive(CurrencyActiveEnum::ACTIVE)
    ->with('latestCurrencyHistory')
    ->orderBy('ordering', 'asc')
    ->get();

生成的SQL会通过row_number()窗口函数按currency_id分组,取每个分组的最新1条记录。但给关联方法添加->limit(1)后,生成的SQL无变化,limit未生效。需要实现两个需求:

  • 确保每个Currency仅关联CurrencyHistory的最后1条数据
  • 添加CurrencyHistory.created_at ≥ 最近24小时的过滤条件

解决方法

1. 使用hasOne关联 + latestOfMany(推荐)

Laravel提供latestOfMany方法专门用于获取关联模型的最新单条记录,替代hasMany更符合“单条记录”的业务场景,同时支持添加过滤条件:

use Illuminate\Database\Eloquent\Relations\HasOne;

public function latestCurrencyHistory(): HasOne
{
    return $this->hasOne(CurrencyHistory::class)
        // 添加最近24小时的过滤条件
        ->where('created_at', '>=', now()->subDay())
        // 指定取最新的1条记录
        ->latestOfMany();
}

执行原预加载查询后,Laravel会生成正确的SQL,确保每个Currency仅关联符合时间条件的最新CurrencyHistory记录。

2. 保持hasMany关联,通过子查询预加载(灵活场景)

如果需要保留hasMany关联的定义,可在查询时使用withSub自定义子查询,实现单条记录获取和时间过滤:

$this->currencies = Currency::getByActive(CurrencyActiveEnum::ACTIVE)
    ->withSub([
        'latestCurrencyHistory' => function ($query) {
            $query->latest()
                ->where('created_at', '>=', now()->subDay())
                ->limit(1);
        }
    ], 'latest_currency_history')
    ->orderBy('ordering', 'asc')
    ->get();

查询结果中,每个Currency实例的latest_currency_history属性会包含符合条件的最新1条CurrencyHistory记录。

原limit(1)不生效的原因

当使用hasMany关联进行预加载时,Laravel会自动检测到“需要为每个父模型获取子记录”的需求,此时直接添加的limit(1)会被框架忽略,转而使用row_number()窗口函数实现按分组取1条记录的逻辑,因此生成的SQL无变化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 21:34:54