Hyperf 3.1.66 新增 whereJsonContainsKey 方法,仅支持 Query Builder(如 DB::table() 或 Model::query()),语法为 →whereJsonContainsKey('column', '$.key'),默认模式 'one',路径须严格符合 JSON Path 规范且字段类型必须为 MySQL JSON。

Hyperf 3.1.66 版本确实新增了对 MySQL JSON 字段「包含键」的原生支持,但不是加个语法糖就完事——它底层复用了 JSON_CONTAINS_PATH,且只在 Query Builder 层做了封装,ORM 模型层默认不生效。
JSON_CONTAINS_PATH 在 Hyperf Query Builder 中怎么用
Hyperf 3.1.66 把 JSON_CONTAINS_PATH 封装进 whereJsonContainsKey 方法,仅限 Query Builder 场景(如 DB::table()),不作用于 Eloquent Model。
- 语法是
->whereJsonContainsKey('column_name', '$.key'),第二个参数必须是标准 JSON 路径字符串,不能是变量拼接 - 第三个可选参数
'one'或'all'控制匹配模式,默认为'one'(存在任意一个路径即命中) - 错误写法:
->whereJsonContainsKey('meta', '$.' . $userInput)—— 路径未白名单校验,可能注入 - 正确写法示例:
DB::table('users')->whereJsonContainsKey('settings', '$.theme')->get()
Eloquent Model 里没法直接用 whereJsonContainsKey
Model 类继承自 Hyperf\Database\Model\Model,其查询构造器不自动代理 whereJsonContainsKey 方法,调用会报 BadMethodCallException。
- 想在 Model 中查 JSON 键,得显式切回 Query Builder:
User::query()->whereJsonContainsKey('settings', '$.notifications')->get() - 别试图在
$casts里加'settings' => 'json'来触发——这只会让字段反序列化成 PHP 数组,跟数据库层面的JSON_CONTAINS_PATH完全无关 - 如果频繁使用,建议封装一个 scope:
public function scopeWhereJsonHasKey(Builder $builder, string $column, string $path) { return $builder->whereJsonContainsKey($column, $path); }
为什么查不到数据?常见路径和类型陷阱
JSON_CONTAINS_PATH 对路径格式和 JSON 类型极其敏感,错一点就返回空结果。
- 路径必须以
$开头,且用单引号包裹(Query Builder 内部会转义),写成'$.user.name'可以,'user.name'或"$.user.name"都不行 - 如果字段值是
null或非 JSON 类型(比如存的是字符串"{...}"而非真正的 JSON 类型),MySQL 会静默返回NULL,导致条件恒假 - 确认字段类型:
SHOW COLUMNS FROM users LIKE 'settings';必须显示json,不是text或varchar - 测试语句优先用原生 SQL 验证:
SELECT * FROM users WHERE JSON_CONTAINS_PATH(settings, 'one', '$.email');
真正麻烦的不是写法,而是当你要查嵌套数组里的某个键是否存在(比如 $.items[*].id)时,MySQL 原生不支持通配符路径匹配——JSON_CONTAINS_PATH 的 'one' 模式只认字面路径,[*] 这种写法会被当作普通字符串处理。这种场景只能退回到 JSON_EXTRACT + IS NOT NULL 组合,或者建虚拟列加索引。


















