Laravel中如何实现基于isOldUser方法的查询作用域?
Laravel User模型老用户筛选查询作用域实现方案
首先要明确:查询作用域是用来构建批量数据库查询的,不能直接复用单个用户的isOldUser方法(因为它依赖缓存且针对单实例),需要把老用户的判断条件转换成数据库层面的关联存在性检查。
实现思路
老用户的核心判断逻辑是同时满足两个条件:
- 用户存在创建时间早于3个月前的治疗方案
- 用户存在符合以下要求的预约记录:
- 预约时间早于3个月前
- 状态为「到店就诊」
- 已完成就诊
- 类型为「就诊」
查询作用域需要根据传入的布尔值,分别筛选符合/不符合上述条件的用户。
代码实现
假设User模型已定义以下关联(请根据实际模型关联调整):
// User.php public function treatments() { return $this->hasMany(Treatment::class); // 治疗方案关联 } public function appointments() { return $this->hasMany(Appointment::class); // 预约记录关联 }
添加查询作用域:
// User.php public function scopeIsOldUserFilter($query, bool $isOldUser) { $threeMonthsAgo = now()->subMonths(3); if ($isOldUser) { // 筛选同时满足两个条件的老用户 $query->whereHas('treatments', function ($treatmentQ) use ($threeMonthsAgo) { $treatmentQ->where('created_at', '<', $threeMonthsAgo); }) ->whereHas('appointments', function ($appointmentQ) use ($threeMonthsAgo) { $appointmentQ->where('appointment_time', '<', $threeMonthsAgo) ->where('status', '到店就诊') // 替换为你的实际字段值 ->where('is_completed', true) // 替换为你的实际字段/值 ->where('type', '就诊'); // 替换为你的实际字段值 }); } else { // 筛选不满足老用户条件的用户:要么无符合条件的治疗方案,要么无符合条件的预约 $query->where(function ($subQ) use ($threeMonthsAgo) { $subQ->whereDoesntHave('treatments', function ($treatmentQ) use ($threeMonthsAgo) { $treatmentQ->where('created_at', '<', $threeMonthsAgo); }) ->orWhereDoesntHave('appointments', function ($appointmentQ) use ($threeMonthsAgo) { $appointmentQ->where('appointment_time', '<', $threeMonthsAgo) ->where('status', '到店就诊') ->where('is_completed', true) ->where('type', '就诊'); }); }); } return $query; }
使用示例
// 获取所有老用户 $oldUsers = User::isOldUserFilter(true)->get(); // 获取所有非老用户 $nonOldUsers = User::isOldUserFilter(false)->get();
注意事项
- 请根据你的数据库字段名,替换代码中
status、is_completed等字段的实际值 - 为了优化查询性能,建议给以下字段添加组合索引:
treatments(user_id, created_at)appointments(user_id, appointment_time, status, is_completed, type)
- 查询作用域无法复用单用户的缓存逻辑,因为批量查询需要直接操作数据库;如果需要缓存批量结果,可以在调用作用域后自行处理缓存。
内容的提问来源于stack exchange,提问作者M a m a D
相关产品推荐
相关产品推荐

