在Laravel模型的关系中,如何使用GROUP BY和MAX返回关系?

时间:2018-08-06 12:53:26

标签: mysql laravel eloquent laravel-5.4

我有一个项目,该项目可以有附加文件。项目和文档都是模型/表格。

简化的示例文档表:

-----------------------------------
| ID  | filename        | version |
-----------------------------------
| 1   | list.docx       | 1       |
| 2   | list.docx       | 2       |
| 3   | file.xls        | 1       |
-----------------------------------

我希望有一些简单的版本控制,以便用户可以“替换”文档,新表行将复制ID和版本以外的所有先前条目值。

我的问题是我想使用一种关系来提取所有最新文档。我目前在Project模型中使用这种怪物:

public function latest_documents()
{
    return $this->hasMany(Document::class)
        ->where('version', \DB::raw('(SELECT max(d.version) from documents d where d.filename = documents.filename)'))
}

必须有更好的方法吗?我尝试仅将groupBy()和max()用于关系,但出现错误。

编辑:在DB :: raw解决方案之前尝试了'Laravel方法':

public function documents()
{
    return $this->hasMany(Document::class)->groupBy('filename')->max('version');
}

错误:

Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation

1 个答案:

答案 0 :(得分:1)

我的建议是基于文档表创建一个MySQL视图,该视图始终仅包含最新的文档文件,并仅与该视图建立关系。所以:

步骤1 /创建视图:

create view latest_documents as
  select filename,
         max(version)  as version,
         project_id    as project_id,
         any_value(id) as id
  from documents
  group by project_id, filename;

第2步/创建视图模型:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class LatestDocument extends Model
{
    //
}

步骤3 /将关系添加到项目模型中:

public function latest_documents()
{
    return $this->hasMany(LatestDocument::class);
}

我对此进行了测试,应该可以工作。

注意:我在第一步中使用any_value()来防止出现根据only_full_group_by的错误。因此,如果您禁用了此模式(我不推荐),则无需在id周围使用此功能。