Laravel Spatie 自定义筛选:基于关联模型最新记录的条件过滤
技术百科
聖光之護
发布时间:2025-12-27
浏览: 次 本文介绍如何在 laravel 中使用 spatie query builder 实现“仅依据关联模型(如最后一次检查)的最新数据进行精准筛选”,解决 `wherehas` 无法限制子查询为单条记录的常见痛点。
在 Laravel 应用中,当需要根据关联模型的最新一条记录(而非任意匹配)进行筛选时,直接使用 whereHas() 配合 orderBy()->limit(1) 是无效的——因为 whereHas 的闭包内排序和限制对主查询无约束力,实际仍会匹配所有符合条件的关联记录,导致逻辑错误(例如:动物曾患病但最新检查已康复,却被误判为“生病”)。
正确方案需分三步完成:
- 获取每个动物最新检查记录的 ID(即按 animal_id 分组后取 MAX(id) 或 MAX(created_at) 对应的主键);
- 基于这些 ID 查询出真正“当前患病”的检查记录(disease_id IS NOT NULL);
- 提取对应 animal_id 并反向筛选动物主表。
以下是经过优化、可直接使用的生产级实现:
groupBy('animal_id');
// 步骤2:连接最新检查记录,并筛选 disease_id 非空的动物
$sickAnimalIds = Examination::query()
->select('animal_id')
->whereIn('id', $subQuery->pluck('max_id'))
->whereNotNull('disease_id')
->pluck('animal_id');
// 步骤3:主查询只保留这些动物
$query->whereIn('id', $sickAnimalIds);
}
}✅ 关键改进说明:
- 避免了 get()->pluck() 导致的 N+1 和内存膨胀问题,改用原生子查询(whereIn(...) 内嵌 SELECT),性能更优;
- 使用 MAX(id) 前提是 id 严格递增且代表时间顺序(若依赖 created_at,请改用 MAX(created_at) 并配合 JOIN 或窗口函数);
- 显式使用 whereNotNull('disease_id') 替代 '!=', null,语义更准确且兼容所有数据
库。
⚠️ 注意事项:
- 若 examinations 表数据量极大,建议为 (animal_id, id) 或 (animal_id, created_at) 添加复合索引;
- Laravel 9+ 可结合 latestOfMany() 关系定义简化逻辑(需模型支持),但自定义 Filter 中仍推荐上述显式子查询方式以保障可控性与兼容性;
- 此方案不依赖 Spatie 的 withMax 辅助方法(该方法仅用于 eager loading,不可用于 where 条件)。
通过该实现,系统将严格依据每只动物最近一次检查结果判断健康状态,确保筛选结果真实反映当前状况,完美契合医疗、IoT 设备状态监控等强时效性业务场景。
# 符合条件
# 自定义
# 更准确
# 而非
# 可直接
# app
# 数据库
# NULL
# select
# php
# 闭包
# 主键
# Filter
# laravel
# iot
# 内嵌
# 仍会
# 每只
# 检查结果
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- LINUX怎么查看进程_LINUX ps命令查看运
- 如何自定义Windows终端的默认配置文件?(Po
- PyTorch DDP 多进程训练在 Kaggle
- c# 在ASP.NET Core中管理和取消后台任
- 如何在 Go 同包不同文件中正确引用结构体
- Win10如何卸载微软拼音输入法 Win10只保留
- mac怎么打开终端_MAC终端Terminal使用
- Win11怎样安装网易云音乐_Win11安装网易云
- Win11如何设置开机问候语 Win11修改登录界
- Windows蓝屏错误0x0000001E怎么修复
- php内存溢出怎么排查_php内存限制调试与优化方
- php485读数据时阻塞怎么办_php485非阻塞
- Windows10怎么查看硬件信息_Windows
- 如何在Golang中处理模块冲突_解决依赖版本不兼
- 如何在Golang中优化文件读写性能_使用缓冲和并
- Linux怎么禁止Root用户远程登录_Linux
- php485支持哪些操作系统_php485跨系统支
- 短链接怎么自定义还原php_修改解码规则适配需求【
- c++20的std::format怎么用 比pri
- mac怎么安装adb_MAC配置Android A
- 如何在Golang中处理模块包路径变化_Golan
- 如何将竖排文本文件转换为横排字符串
- php转mp4怎么设置帧率_调整php生成mp4视
- MAC如何修改默认应用程序_MAC文件后缀关联设置
- Win11色盲模式怎么开_Win11屏幕颜色滤镜设
- Win11怎么查看wifi信号强度_检测Windo
- c# 服务器GC和工作站GC的区别和设置
- Win11输入法切换快捷键怎么改_Windows
- Windows 10怎么录屏_Windows 10
- 如何在Golang中使用container/hea
- 如何在Golang中使用内置函数_Golangle
- php中self::能调用子类重写的方法吗_静态绑
- Win11开始菜单打不开_修复Windows 11
- c++如何使用std::bind绑定函数参数_c+
- Win11怎么开启专注模式_Windows11时钟
- Windows系统被恶意软件破坏后的恢复策略_错误
- 新手学PHP架构总混淆概念咋办_重点梳理【教程】
- Win11怎么关闭定位服务 Win11禁止应用获取
- 如何使用Golang写入二进制文件_Golang
- 如何使用Golang管理跨项目依赖_Golang多
- Win11怎么关闭搜索历史_Win11清除设备上的
- Python函数缓存机制_lru_cache解析【
- Windows10怎么用“讲述人”读屏辅助 Win
- Python文件操作优化_大文件与流处理解析【教程
- Win10怎么创建桌面快捷方式 Win10为应用创
- c++ std::future和std::prom
- PythonFastAPI项目实战教程_API接口
- 如何使用Golang实现基本类型比较_Golang
- Go 中实现 Python urllib.quot
- Mac如何解压zip和rar文件?(推荐免费工具)

库。
QQ客服