Laravel eloquent apply whereHas on the latest record of hasMany 关系
Posted
技术标签:
【中文标题】Laravel eloquent apply whereHas on the latest record of hasMany 关系【英文标题】:Laravel eloquent apply whereHas on latest record of hasMany relationship 【发布时间】:2020-10-02 15:57:43 【问题描述】:使用 Laravel 7.0
我有 3 个模型(Meeting、MeetingVersion 和 User), 和 4 个表格(Meeting、meeting_versions、users、meeting_versions_users)。
一个Meeting有很多MeetingVersion模型,其中每个版本都与User有many-to-many
关系。每个 MeetingVersion 都有一个指向其父 Meeting 的外键 meeting_id
。用户通过 meeting_versions_users
数据透视表关联到一个 MeetingVersion。
现在,我想选择最新版本与给定用户 ID 相关联的所有会议。
会议课
public function versions()
return $this->hasMany(MeetingVersion::class, 'meeting_id');
MeetingVersion 类
public function users()
return $this->belongsToMany(User::class, 'meeting_versions_users', 'version_id', 'user_id');
表格
会议
+----+
| id |
+----+
| 10 |
| 11 |
+----+
meeting_versions
+----+------------+---------+
| id | meeting_id | version |
+----+------------+---------+
| 31 | 10 | 1 |
| 32 | 10 | 2 |
| 33 | 10 | 3 | <- latest version (33) for meeting id 10
| 34 | 11 | 1 |
| 35 | 11 | 2 | <- latest version (35) for meeting id 11
+----+------------+---------+
meeting_versions_users
+------------+---------+
| version_id | user_id |
+------------+---------+
| 31 | 101 |
| 32 | 101 |
| 33 | 102 | <- user associated with latest version for meeting id 10
| 34 | 101 |
| 35 | 101 | <- user associated with latest version for meeting id 11
+------------+---------+
用户
+-----+
| id |
+-----+
| 101 |
| 102 |
+-----+
这是我正在尝试的查询。我应该只返回会议 11,但此查询返回用户 101 的两个会议。
// Some user id.
$userId = 101;
// Query to get all meetings where user is associated with latest version of meeting.
$meeting = Meeting::query()->where(function (Builder $query) use ($userId)
$query->whereHas('versions', function (Builder $query) use ($userId)
/*
* I want to get just the "latest" version model here, so that further queries are constrained to that model only.
* As it is now, the below whereHas query is applied to all child models.
* Using $query->latest('version')->limit(1) doesn't work here as expected.
*
* So, I need to a way to limit the following whereHas query to the latest version.
* This constraint should be applied to just the "latest" model relation, instead of all models.
*/
$query->whereHas('users', function (Builder $query) use ($userId)
$query->where('id', $userId);
);
);
)->get();
非常感谢任何帮助。
【问题讨论】:
【参考方案1】:在你的问题中你说:
在此处使用 $query->latest('version')->limit(1) 无法按预期工作。
因为 laravel 得到了整个查询的最后一个 MeetingVersion!不是每次会议
解决这个问题使用eloquent-eager-limit
安装它:
composer require staudenmeir/eloquent-eager-limit:"^1.0"
然后在会议模型中:
class Meeting extends Model
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
.....
public function lastMeetingVersion()
return $this->hasMany(MeetingVersion::class, 'meeting_id')
->orderBy('id','desc')->limit(1);
在 MeetingVersion 中:
class MeetingVersion extends Model
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
......
现在限制将按您的预期工作......
$meeting = Meeting::query()->with(['lastMeetingVersion' => function ($query)
use ($userId)
$query->whereHas('users', function ($q) use ($userId)
$q->where('id', $userId);
);
]);
更多详情请见:eloquent-eager-limit
【讨论】:
谢谢,OMR。我尝试了这个解决方案,但我也没有工作。在此查询的末尾添加->get()
时,出现内存已耗尽错误。我也只是尝试使用->find(10)
,它返回一个结果,但对两个用户都这样做,而不是用户用户 102。【参考方案2】:
您可以使用 subselect 来获取每个会议的最大版本 ID。
$meetings = Meeting::query()
->whereHas('versions', function (Builder $query) use ($userId)
$query->addSelect([
'max_meeting_version_id' => MeetingVersion::select('id')->whereColumn('meeting_id', 'meeting.id')
->orderBy('version', 'desc')->limit(1)
])->whereHas('users', function (Builder $query2) use ($userId)
$query2->where('users.id', $userId);
)
->havingRaw('max_meeting_version_id = meeting_versions.id');
)
->get();
【讨论】:
谢谢,邦诺基亚。我试过这个,但在havingRaw
子句中出现错误。 “未找到列:1054 Unknown column 'meeting_versions.id' in 'have Clause'” 我尝试将子句更改为 'max_meeting_version_id = id',从而防止出现错误。但是,现在它没有产生任何结果。
你有 laravel 调试栏吗,它可以显示原始的 sql 查询。我不确定为什么meeting_versions.id
不知道。以上是关于Laravel eloquent apply whereHas on the latest record of hasMany 关系的主要内容,如果未能解决你的问题,请参考以下文章
Laravel/Lumen - 使用 Model::with()
php Laravel 5 Eloquent CheatSheet #laravel #eloquent
php Laravel 5 Eloquent CheatSheet #laravel #eloquent
php Laravel 5 Eloquent CheatSheet #laravel #eloquent
php [Eloquent CheatSheet] Eloquent #laravel #eloquent的常见查询方法