Laravel 8+ 原生支持 whereJsonContains,适配 MySQL 5.7+ 的 JSON_CONTAINS 和 PostgreSQL 的 @> 操作符;需确保字段类型正确(MySQL 用 JSON、PostgreSQL 用 JSONB)、路径使用 -> 分隔、传值非 JSON 字符串,且建议为 JSON 字段添加数据库索引以提升性能。

whereJsonContains 在 Laravel 8+ 中原生支持,无需自定义
如果你正在用 Laravel 8 或更高版本(包括 Laravel 9/10),whereJsonContains 已是查询构建器的内置方法,直接调用即可,不用写扩展或 macro。Laravel 底层已适配 MySQL 5.7+ 的 JSON_CONTAINS 和 PostgreSQL 的 @> 操作符。
常见错误是升级了 Laravel 却还在查旧文档,以为要手动加 macro —— 实际上只要数据库驱动正确、JSON 字段类型声明得当,whereJsonContains 就能跑起来。
- MySQL 要求字段类型为
json(不是text),且 MySQL 版本 ≥ 5.7 - PostgreSQL 需使用
jsonb类型(json不支持索引和@>) - SQLite 不支持该方法(会抛出
BadMethodCallException)
正确写法:传参顺序和值格式很关键
whereJsonContains 的第二个参数是「要匹配的值」,不是 JSON 字符串,也不是键路径表达式 —— 它只匹配 JSON 数组中的元素或对象的顶层值。比如字段存的是 ["apple", "banana"],你想查含 "apple",就直接传字符串;如果存的是 {"tags": ["php", "laravel"]},想查 tags 数组含 "laravel",就得用点号路径:tags。
示例:
// ✅ 正确:字段值是 JSON 数组
User::whereJsonContains('preferences', 'dark_mode')->get();
<p>// ✅ 正确:字段值是对象,查嵌套数组
Post::whereJsonContains('meta->tags', 'laravel')->get();</p><p>// ❌ 错误:传了 JSON 字符串(会被当字面量匹配)
User::whereJsonContains('preferences', '"dark_mode"')->get();</p><p>// ❌ 错误:路径写成 'preferences.tags'(Laravel 要求 -> 分隔)
Post::whereJsonContains('meta.tags', 'laravel')->get();
低版本 Laravel(
Laravel 7 及更早版本没有 whereJsonContains,但可以手动注册 macro,不过要注意两点:一是避免覆盖未来版本原生方法,二是必须检查数据库类型再拼 SQL,否则在 SQLite 或旧 MySQL 上会崩。
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
推荐在 AppServiceProvider::boot() 中加带保护的 macro:
use Illuminate\Database\Query\Builder;
<p>Builder::macro('whereJsonContains', function ($column, $value, $boolean = 'and') {
if (! $this->grammar->supportsJson()) {
throw new RuntimeException('JSON operations not supported by current database driver');
}</p><pre class="brush:php;toolbar:false;">return $this->where($column, 'LIKE', "%\"{$value}\"%", $boolean);});
⚠️ 这个 fallback 用 LIKE 是临时方案,仅适用于简单字符串匹配,不支持嵌套对象或数组结构判断,且无法利用 JSON 索引 —— 所以仅限开发过渡,上线前务必升级 Laravel 或改用原生支持版本。
性能和索引:JSON 字段查得慢?先建函数索引
即使语法跑通,whereJsonContains 在大数据量下可能全表扫描。MySQL 需要为具体路径建函数索引,例如:
-- MySQL 8.0+,为 meta->tags 建索引 ALTER TABLE posts ADD COLUMN tags_json JSON AS (meta->'$.tags'); ALTER TABLE posts ADD INDEX idx_tags_json (tags_json);
PostgreSQL 则需用 jsonb_path_ops 索引:
CREATE INDEX CONCURRENTLY idx_posts_meta_tags ON posts USING GIN ((meta->'tags') jsonb_path_ops);
没加索引时,哪怕只有几千条记录,whereJsonContains 也可能比普通 where 慢一个数量级 —— 这点很容易被忽略,直到线上查慢告警才反应过来。

















