Laravel eloquent 获取相关表的最新行

Posted

技术标签:

【中文标题】Laravel eloquent 获取相关表的最新行【英文标题】:Laravel eloquent get the latest row of related table 【发布时间】:2017-09-21 21:04:05 【问题描述】:

我有两张桌子,书籍章节。一本书有很多章节。

图书模型:

public function chapters() 
   return $this->hasMany(Chapter::class);

章节模型:

public function book() 
   return $this->belongsTo(Book::class);

我想使用这样的单个查询来获取带有自己最新章节的书单:

$books = Book::with(['authors', 'categories', 'chapters' => function($q) 
   $q->orderBy('updated_at', 'desc')->first();
]->get();

但它不起作用。章节返回一个空数组。如果我在子查询中删除 first(),它可以正常工作。

有没有办法只用一个查询来做到这一点。我不想获取所有相关章节然后保留一个或使用多个查询。我感觉更好的唯一方法是使用 join,对吗?

任何帮助将不胜感激。谢谢!

【问题讨论】:

不,Eloquent 就足够了。使用limit() 或者看看here 怎么样。您需要做的是将$q->orderBy('updated_at', 'desc') 限制为1。 一本书可能有超过 5k 的章节,我应该把它们都拿下来吗,内存问题? 您需要将查询限制到一行。 我试过了,但它对空结果不起作用。 @Alex 您不能将limit 添加到急切加载的关系中。假设你有 10 本书,每本书有 10 章(共 100 章)。如果将 limit(1) 添加到预先加载的 chapters 关系中,这将使关系查询总共获取 1 章,而不是每本书 1 章。 【参考方案1】:

因为关系是单独的查询,所以您不能对预先加载的关系添加限制。如果这样做,这会限制整个关系查询,而不是作为每个相关对象的限制。

幸运的是,您的要求可以通过附加关系简单地实现:

public function latestChapter() 
    return $this->hasOne(Chapter::class)->latest();

现在,您可以直接加载新的 latestChapter 关系,而不是急切加载整个 chapters 关系。

$books = Book::with(['authors', 'categories', 'latestChapter'])->get();

【讨论】:

奇怪,我之前用 function lastest_chapter() return $this->chapters()->take(1); 试过这个并且它不起作用。在您的帖子中,它应该是 hasMany 并使用 take(1) 限制结果。感谢您的回答! @trinvh 我特意将其设为hasOne 关系。最新的只有一章,不多。 啊,但在我的情况下,我必须按 sort_order 列进行过滤。无论如何,谢谢! @trinvh latest() 只是->orderBy('created_at', 'desc') 的快捷方式。您可以将所需的任何条件添加到关系中。例如return $this->hasOne(Chapter::class)->orderBy('sort_order', 'desc'); 这不是正确的答案,因为它没有按预期工作。生成了错误的 SQL 查询,该查询获取所有章节而不是每本书一章【参考方案2】:

我知道这是一个旧帖子,但有一些新的解决方案,我想与您分享。 在 laravel 8 中,有新的辅助函数:latestOfMany、oldestOfMany 和 ofMany。 对于您的示例,您可以使用:

public function latestChapter() 
    return $this->hasOne(Chapter::class)->latestOfMany();

【讨论】:

【参考方案3】:

对于那些无法将 laravel 8.4 升级到 ->latestOfMany 方法的人,可以通过自连接来增强 hasOne 关系,以过滤每个主要模型的最新相关模型

public function lastchapter()

    return $this->hasOne(Chapter::class)->join(DB::raw("(
           SELECT MAX(id) as id, book_id
           FROM `books` as `books_sub`
           GROUP BY book_id
        ) as lastchapters"), function ($join) 
        $join->on("lastchapters.id", '=', "books.id");
    )->whereRaw('lastchapters.id = books.id');

【讨论】:

以上是关于Laravel eloquent 获取相关表的最新行的主要内容,如果未能解决你的问题,请参考以下文章

Laravel Eloquent 关系 - 不根据条件获取

Laravel Eloquent:如何通过 whereHas() 方法获取相关记录?

如何使用Laravel Eloquent获取相关城市的国家名称

Laravel Eloquent在相关模型上按范围获取模型

急切加载 Laravel Eloquent 相关模型

Laravel 4 Eloquent 获取关系 ID