Laravel 8 如何用原生查询过滤Collection,实现未验证邮箱用户按提醒状态分类
错误原因分析
你现有代码存在两个问题:
- 语法报错:
$reminded仅构造了查询构造器实例,没有执行查询,本身不支持isEmpty()方法,你可以调用->exists()来判断是否存在匹配记录。 - 逻辑错误:你需要的「未发过提醒的用户」是
verification_reminders表不存在对应用户记录,而你写的查询条件是匹配表中存在记录且两个提醒字段都为null的情况,和需求不符。
更简洁的实现方案(推荐)
用Laravel自带的关联查询实现,避免N+1性能问题,代码更易读:
步骤1:给User模型添加关联
在app/Models/User.php中添加一对一关联:
public function verificationReminder() { return $this->hasOne(\App\Models\VerificationReminder::class); }
如果没有创建VerificationReminder模型,也可以直接用原生查询实现,见下方备选方案。
步骤2:直接查询两类用户
不需要先查所有未验证用户再过滤,直接用whereDoesntHave和whereHas分两次查询即可:
// 1. 未发过提醒的用户 $users_not_reminded = User::whereNull('email_verified_at') ->whereDoesntHave('verificationReminder') ->get(); // 2. 已发首次提醒的用户 $users_first_reminded = User::whereNull('email_verified_at') ->whereHas('verificationReminder', function ($query) { $query->whereNotNull('first_reminder') ->whereNull('second_reminder'); }) ->get();
不使用模型关联的备选方案
如果不想创建提醒表的模型,也可以用whereExists直接写查询:
// 未发过提醒的用户 $users_not_reminded = User::whereNull('email_verified_at') ->whereNotExists(function ($query) { $query->from('verification_reminders') ->whereRaw('user_id = users.id'); }) ->get(); // 已发首次提醒的用户 $users_first_reminded = User::whereNull('email_verified_at') ->whereExists(function ($query) { $query->from('verification_reminders') ->whereRaw('user_id = users.id') ->whereNotNull('first_reminder') ->whereNull('second_reminder'); }) ->get();
内容的提问来源于stack exchange,提问作者Kali FR
相关产品推荐
相关产品推荐

