导读:本期聚焦于小伙伴创作的《Laravel模型如何查询JSON字段?实操方法与常见坑位解析》,敬请观看详情。把订单扩展信息塞进MySQL的JSON列后,用Laravel模型直接取数据常出现找不到值或类型不对的问题。其实Eloquent从5.7开始就原生支持JSON字段的where查询,借助-操作符能直接指向键路径。不过不同数据库对JSON函数实现差异很大,MySQL用JSON_EXTRACT,PostgreSQL走-语法,SQLite又另有一套。本文理清在模型里如何用whereJsonContains、whereJsonLength以及箭头语法做等值、包含和长度判断,并指出索引缺失导致全表扫描、键名大小写敏感、嵌套数组查询写法错误等高频误区,帮你写出稳定可迁移的查询代码。

在Laravel项目里,把配置项、扩展属性存放到数据库的JSON类型字段已经成为常见做法。相较于早年用TEXT存序列化字符串,原生JSON列既能保证结构,又能让数据库层参与检索。不过很多人在用Eloquent模型查询这些字段时,写法和平常的字段不一样,容易写出不报错但查不到数据的语句。

Laravel模型如何查询JSON字段?实操方法与常见坑位解析

一、JSON字段在Laravel模型中的基本映射

首先要在迁移文件中把字段声明为JSON类型,Laravel的Schema builder提供了对应的方法。这样数据库会真正以JSON格式存储,而不是纯文本。模型里一般不需要特殊转换,因为Laravel会自动把JSON列反序列化成数组或对象。

<?php

use IlluminateDatabaseMigrationsMigration;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;

class CreateOrdersTable extends Migration
{
    public function up()
    {
        Schema::create('orders', function (Blueprint $table) {
            $table->id();
            // 声明为JSON类型,存储扩展信息
            $table->json('extra');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('orders');
    }
}

当使用模型读取记录时,$order->extra 得到的是一个数组。如果写入时传的是数组,Eloquent会自动调用 json_encode 再入库。这种透明转换让我们在业务层像操作普通属性一样使用,但在构造查询条件时,必须告诉查询构造器这是在查JSON路径。

需要注意的是,JSON字段的键名区分大小写,且数据类型也会被保留。例如存入的是字符串"1"和数字1,在JSON里是不同的,用等值查询时类型不对就匹配不上。这点和普通字符串列隐式转换行为不一样,是初学者经常忽略的。

二、使用箭头语法做等值查询

Laravel提供了 -> 操作符作为JSON路径的简写。在where方法里,把字段和键用箭头连接,就能生成对应数据库的JSON提取函数。以MySQL为例,extra->status 最终会被编译成 JSON_EXTRACT(extra, '$.status')。

<?php

use AppModelsOrder;

// 查询extra中status为paid的订单
$paidOrders = Order::where('extra->status', 'paid')->get();

// 嵌套路径查询,extra里的user对象中的level键
$vipOrders = Order::where('extra->user->level', 'vip')->get();

上面的写法在MySQL 5.7及以上、PostgreSQL、SQLite中都能工作,Laravel会根据连接驱动翻译为合适的SQL。不过箭头语法默认做的是等值比较,且对值的类型有要求。如果你存的是布尔值,就不能用字符串'true'去匹配,而要传真正的布尔变量。

另外,当JSON里的值是字符串时,部分数据库返回的提取结果会带有引号,Laravel做了处理让比较直观,但如果你自己写原生JSON函数就要小心外层引号。建议优先用Eloquent提供的封装,减少数据库差异带来的坑。

三、whereJsonContains查询数组包含关系

如果JSON字段里存的是数组,比如extra中的tags是一个标签列表,要判断某条记录是否包含某个标签,就不能用等值。Laravel给出了 whereJsonContains 方法,它会生成对应数据库的数组包含检测语句。

<?php

use AppModelsOrder;

// 查询tags数组中包含'sale'的订单
$saleOrders = Order::whereJsonContains('extra->tags', 'sale')->get();

// 同时包含多个值
$multiOrders = Order::whereJsonContains('extra->tags', ['sale', 'new'])
    ->get();

在MySQL中,该方法映射为 JSON_CONTAINS 函数;PostgreSQL使用 ? 或 @> 操作符;SQLite也有自己的实现。这种抽象让我们可以写一套代码跑在不同数据库上。但需要注意,MySQL的JSON_CONTAINS对类型和顺序敏感,包含多个值时,数组顺序不影响,但类型必须一致。

如果数据库版本较老,比如MySQL 5.6并不支持原生JSON类型,那么这些方法会失效或者直接报错。因此在团队开发前,务必确认生产库版本,并在测试环境覆盖多种数据库的查询用例。

四、whereJsonLength判断数组长度

有时我们需要筛选出JSON数组长度满足条件的记录,例如extra里的items数组为空代表无效订单。Laravel的 whereJsonLength 可以轻松实现。

<?php

use AppModelsOrder;

// 查询items数组长度大于0的订单
$validOrders = Order::whereJsonLength('extra->items', '>', 0)->get();

// 精确等于3
$threeItemOrders = Order::whereJsonLength('extra->items', 3)->get();

这个方法在底层同样做了数据库适配,比自己写原生JSON_LENGTH更省心。但要注意,如果路径指向的不是数组而是对象,长度指的是键值对数量,行为符合JSON规范。在复杂报表统计时,配合索引使用能明显提升速度。

由于JSON函数通常无法有效利用普通索引,当数据量很大时,这类查询可能变慢。MySQL支持对JSON字段生成虚拟列并加索引,Laravel迁移里可以用 virtualAs 配合索引来优化热点查询,这属于进阶但非常实用的手段。

五、常见误区与避坑建议

第一个常见误区是键名拼写和大小写。JSON里的 Statusstatus 是两个不同的键,用模型查询时写错就不会返回数据,而且不会报异常,排查起来很隐蔽。建议在模型里定义JSON字段的访问器,统一键名规范。

<?php

namespace AppModels;

use IlluminateDatabaseEloquentModel;

class Order extends Model
{
    // 定义访问器,统一读取extra里的status
    public function getExtraStatusAttribute()
    {
        return $this->extra['status'] ?? null;
    }
}

第二个误区是误以为JSON查询能走主键索引。实际上大多数JSON路径查询会触发全表扫描,在百万级数据表上响应时间陡增。对于高频过滤字段,应提取为独立列或虚拟列加索引。第三个误区是在事务中频繁更新JSON大字段,造成行锁竞争,必要时可以拆分存储。

最后,在写单元测试时,不要只测MySQL。如果项目可能切换数据库,用Laravel的数据库刷新和多连接测试,确保 whereJsonContains 等写法在目标环境都正确。理清这些点,就能在模型中安稳地使用JSON字段查询。

LaravelJSON字段查询Eloquent修改时间:2026-08-06 04:57:33

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。