laravel json嵌套查询需按数据库适配语法:mysql用双下划线转箭头路径并注册全局钩子;postgresql用whereraw配合#>>及路径数组;sqlite仅支持一级路径,深层需php层解析或拆表。

在 Laravel 中对 JSON 字段做嵌套路径查询时,若直接用点号写法(如 meta.info.name)会导致查询始终返回空,因为 Eloquent 不识别这种结构——它只认数据库原生支持的 JSON 路径语法,且不同数据库写法差异极大,必须严格按驱动适配。
MySQL 中用双下划线替代箭头语法
MySQL 8.0+ 支持 -> 和 ->> 操作符,但 Laravel 的 where() 方法底层会自动转义为 JSON_EXTRACT(),此时字段路径不能含点号。你得把 profile.address.city 写成 profile__address__city。
第一步:在模型中定义访问器,把双下划线自动转为箭头路径
第二步:重写 where() 的键名映射逻辑,在查询前将 profile__address__city 替换为 profile->address->city
第三步:调用时直接写 User::where('profile__address__city', 'Beijing')->get(),无需手动拼接箭头
这一步操作起来很简单,直接把文件拖进去就行。但注意:【必须在 AppServiceProvider 的 boot() 中注册全局键名重写钩子,否则仅在控制器里改无效】
PostgreSQL 中路径必须用单引号包裹
PostgreSQL 使用 #> 和 #>> 操作符提取 JSON 值,路径需为文本数组格式,例如 '{profile,address,city}'。Laravel 默认不支持这种写法,必须显式调用 whereRaw()。
方法一:用 whereRaw() 手写完整表达式
User::whereRaw("? #>> ? = ?", ['profile', '{profile,address,city}', 'Beijing'])->get()
方法二:封装成作用域,在 User 模型中添加 scopeWhereJsonPath(),接收路径数组和值,内部拼接 #>> 表达式
方法三:升级到 Laravel 11+ 后可启用 json_path 宏,但当前稳定版仍需手动处理
SQLite 中禁止使用深层嵌套路径
SQLite 的 JSON1 扩展仅支持一级路径提取,info->name 可用,info->address->city 会直接报错 “no such function: json_extract”。遇到多层结构必须先用 selectRaw() 提取中间层,再用 PHP 层解析。
① 先查出原始 JSON 字段:User::select('id', 'profile')->get()
② 遍历结果,用 json_decode($user->profile, true)['address']['city'] ?? null 判断
③ 筛选后重新构造集合:collect($users)->filter(fn($u) => $u['city'] === 'Beijing')
这招适合数据量小于 500 条的场景;超过就得改表结构,把深层字段拆成独立列,否则全表扫描不可避免。











