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

如何在Laravel Eloquent中获取关联表不同Key的首条记录?

解决方案:Laravel关联查询同时获取多key的最早记录

你遇到的问题是因为两次调用with('history')时,后一次的查询条件会覆盖前一次,最终只返回最后一个key的结果。下面提供几种可行的解决方法:

方法一:定义独立关联(最直观)

在Task模型中为每个需要的key单独定义hasOne关联:

// Task.php
public function historyKey1()
{
    // 取key=1的最早记录
    return $this->hasOne(History::class)->where('key', 1)->orderBy('date', 'asc');
}

public function historyKey2()
{
    // 取key=2的最早记录
    return $this->hasOne(History::class)->where('key', 2)->orderBy('date', 'asc');
}

查询时同时加载这两个关联:

$task = Task::where('id', 1)
    ->with(['historyKey1', 'historyKey2'])
    ->first();

如果需要将结果合并到history数组中,可以在模型里添加访问器:

// Task.php
public function getHistoryAttribute()
{
    $histories = [];
    if ($this->historyKey1) $histories[] = $this->historyKey1;
    if ($this->historyKey2) $histories[] = $this->historyKey2;
    return $histories;
}

方法二:数据库层面直接筛选(效率最优)

通过子查询获取每个key对应的最早日期,再关联查询目标记录:

$task = Task::where('id', 1)
    ->with(['history' => function ($query) {
        $query->whereIn('key', [1, 2])
              ->whereRaw('(task_id, `key`, date) IN (
                  SELECT task_id, `key`, MIN(date) 
                  FROM histories 
                  WHERE task_id = ? AND `key` IN (1,2)
                  GROUP BY task_id, `key`
              )', [1]);
    }])
    ->first();

注意:histories是History表的默认复数表名,若你的表名不同请替换;?绑定task_id用于避免SQL注入。

方法三:集合层面处理(灵活)

先查询所有符合key的记录,再通过集合分组提取最早记录:

$task = Task::where('id', 1)
    ->with(['history' => function ($q) {
        $q->whereIn('key', [1, 2])->orderBy('date', 'asc');
    }])
    ->first()
    ->transform(function ($task) {
        // 按key分组,取每组第一条(已按日期升序,第一条即为最早)
        $task->history = $task->history->groupBy('key')
            ->map(fn($group) => $group->first())
            ->values();
        return $task;
    });

原问题原因说明

Laravel中多次调用with()加载同一个关联时,后续的查询闭包会完全覆盖之前的设置,不会合并条件。所以你第二次调用with('history')会替换第一次的关联逻辑,最终只返回key=2的结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 13:23:13