跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

PHP怎么实现Eloquent JSON Queries JSON查询_Laravel非结构化数据操作【方法】

MySQL 5.7+ 中 whereJsonContains 用于查询 JSON 字段是否包含指定值,要求字段类型为 JSON、路径语法正确(如 'options->tags')、数据为合法 JSON 格式,且不走索引需配合生成列优化性能。 MySQL 5.7+ 直接查 JSON 字段的 whereJsonContains 怎么用 只要数据库是 MySQL 5.7 或更高版本,Eloquent 原生支持
whereJsonContains
、
whereJsonLength
、
whereJsonDoesntContain
这类方法,不用手写 raw 查询。它底层调用的是 MySQL 的
JSON_CONTAINS()
函数,要求字段类型是
json
(不是
text
或
longtext
)。 常见错误是字段用了
text
类型却硬套 JSON 查询——会静默失败或返回空结果,因为 MySQL 不识别其为合法 JSON。
whereJsonContains('options->tags', 'vue')
:查
options
字段里
tags
数组是否包含字符串
"vue"
(注意引号,值必须是完整 JSON 值)
whereJsonContains('meta->permissions', ['read', 'write'])
:查
permissions
数组是否同时包含这两个字符串(顺序无关) 如果字段名带点(如
user.profile
),不能直接写
user.profile->name
,得用
user->profile->name
或改用
whereRaw
Laravel 9+ 的 whereJsonContains 不生效?检查这三点 不是语法写错,而是环境或数据结构不匹配。最常踩的坑是 JSON 数据本身格式不对。 数据库存的是字符串
"[\"vue\",\"laravel\"]"
(转义双引号),而不是真正的 JSON 数组
["vue","laravel"]
——
whereJsonContains
会返回空,因为 MySQL 拒绝解析非法 JSON Eloquent 模型没加
$casts = ['options' => 'array']
,导致存入时没走 JSON 编码,实际存的是序列化字符串(
a:2:{i:0;s:4:"vue";i:1;s:8:"laravel";}
),这种根本不是 JSON 查询路径用了单引号:
'options->'tags''
,PHP 解析后变成
options->'tags'
,MySQL 报错
Invalid JSON path expression
;必须统一用双引号或不加引号(如
options->tags
) PostgreSQL 怎么查 JSONB 字段?别硬套 MySQL 写法 PostgreSQL 用的是
jsonb
类型和
@>
操作符,Eloquent 的
whereJsonContains
在 PG 下会自动编译成
jsonb @> ?
,但前提是字段定义为
jsonb
,且数据是标准 JSONB 格式。 立即学习 “ PHP免费学习笔记(深入) ”; 如果你手动写了
whereRaw("meta @> ?", ['{"role": "admin"}'])
,要注意:传入的必须是 JSON 字符串字面量,不是 PHP 数组。Laravel 自动处理了这个转换,所以优先用 Eloquent 方法而非 raw。 查嵌套对象:
whereJsonContains('meta->settings->theme', 'dark')
在 PG 和 MySQL 都可用,但 PG 要求
settings
和
theme
都存在,否则报错;MySQL 更宽松,路径不存在时返回 false 想查 key 是否存在(不管值),用
whereRaw("meta ? 'role'")
(PG)或
whereRaw("JSON_EXTRACT(meta, '$.role') IS NOT NULL")
(MySQL) PG 对大小写敏感,
'Admin'
≠
'admin'
;MySQL 默认也敏感,除非字段用 utf8mb4_bin 排序规则 复杂 JSON 查询性能差?加生成列 + 索引才是正解 单纯在 JSON 字段上建索引(比如
INDEX(options)
)对 MySQL 5.7+ 没用,JSON 类型不支持普通 B-Tree 索引。必须用生成列(generated column)把要查的路径“抽出来”,再给它加索引。 例如经常按
options->$.status
查询,就在迁移里加:
DB::statement("ALTER TABLE users ADD COLUMN options_status VARCHAR(20) AS (JSON_UNQUOTE(JSON_EXTRACT(options, '$.status'))) STORED"); DB::statement("CREATE INDEX idx_users_options_status ON users(options_status)");
之后就可以用
where('options_status', 'active')
,速度接近普通字段查询。别指望
whereJsonContains
走索引——它永远全表扫描,只是语法方便而已。 PostgreSQL 可以直接在 json b 上建 GIN 索引:
CREATE INDEX idx_meta_gin ON users USING GIN (meta)
,但只加速
@>
、
?
这类操作,对
->>
提取后比较仍需配合表达式索引。

相关文章