Laravel 查询 JSON 列:高效筛选包含数组中任意值的记录
发布时间 - 2026-01-01 00:00:00 点击率:次本文详解如何在 laravel 8 中使用 query builder 对 json 数组列(如 `location_ids`)进行高效过滤,支持“至少匹配一个”语义,并提供 `wherejsoncontains` 循环方案与 mysql 8.0.17+ 推荐的 `json_overlaps` 原生函数两种实现方式。
在 Laravel 应用中,当关联表的 JSON 列(例如 location_ids)存储字符串化整数数组(如 ["1", "2", "5"]),而我们需要筛选出该 JSON 数组中至少包含 $locations(整型数组,如 [1, 3, 7])中任一元素的记录时,不能直接传入数组调用 whereJsonContains —— 因为该方法默认将整个参数作为单个值进行子串/元素匹配,而非集合交集判断。
✅ 推荐方案一:使用 JSON_OVERLAPS(MySQL ≥ 8.0.17)
若数据库版本支持(推荐生产环境优先采用),JSON_OVERLAPS 是最简洁、高效且语义清晰的原生方案。它直接判断两个 JSON 文档是否存在公共元素(自动处理类型转换与嵌套数组):
public function scopeViewable($query)
{
$user = Auth::user();
$locations = $user->getShopAccess()->pluck('id')->values(); // 确保索引连续,避免 toJson() 产生关联数组
if ($user->hasPermissionTo('users.index')) {
return $query->whereHas('shopAccess', function (Builder $q) use ($locations) {
$q->whereRaw('JSON_OVERLAPS(location_ids, ?)', [$locations->toJson()]);
});
}
return $query->whereNull('id'); // 或其他默认限制逻辑
}⚠️ 注意事项:
- pluck('id')->values() 确保生成标准数值索引数组(如 [0 => 1, 1 => 3]),否则 toJson() 可能输出 {"0":"1","1":"3"}(对象格式),导致 JSON_OVERLAPS 匹配失败;
- location_ids 列值必须为合法 JSON 数组(如 ["1","2","5"]),且数据库字符集需为 utf8mb4;
- 此方法在 MySQL 层完成计算,性能远优于 PHP 循环 + 多次 OR,且可利用生成列 + 索引进一步优化(如添加 JSON_CONTAINS 虚拟列索引)。
✅ 方案二:兼容低版本 MySQL 的 whereJsonContains 循环
若数据库版本低于 8.0.17,可退而求其次,对 $locations 数组逐项调用 whereJsonContains 并组合为 OR 条件:
public function scopeViewable($query)
{
$user = Auth::user();
$locations = $user->getShopAccess()->pluck('id')->toArray();
if ($user->hasPermissionTo('users.index')
) {
return $query->whereHas('shopAccess', function (Builder $q) use ($locations) {
$q->where(function ($sub) use ($locations) {
foreach ($locations as $location) {
// 将整数转为字符串,匹配 JSON 中的 "1"、"2" 等
$sub->orWhereJsonContains('location_ids', (string) $location);
}
});
});
}
return $query->whereNull('id');
}? 关键细节:
- whereJsonContains('location_ids', '1') 能正确匹配 ["1","2","5"],但不能匹配 ["10","11"](精确元素匹配,非子串);
- 必须将整型 $location 显式转为字符串 (string) $location,否则 Laravel 可能传递整数 1,而 JSON 中存储的是字符串 "1",导致匹配失败;
- 当 $locations 较大时(如 > 100 项),生成的 SQL OR 链过长可能影响查询计划,建议配合缓存或预聚合优化。
? 总结与选型建议
| 方案 | 适用场景 | 性能 | 可维护性 | 备注 |
|---|---|---|---|---|
| JSON_OVERLAPS | MySQL ≥ 8.0.17 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 推荐首选;一行代码,语义明确,数据库原生优化 |
| orWhereJsonContains 循环 | 兼容旧版 MySQL | ⭐⭐☆ | ⭐⭐⭐ | 注意字符串转换与数组结构;适合中小规模数据 |
无论采用哪种方式,请务必在 shop_access 表的 location_ids 列上建立生成列(Generated Column)并添加索引以提升查询性能,例如:
ALTER TABLE shop_access ADD COLUMN location_ids_json JSON AS (CAST(location_ids AS JSON)) STORED, ADD INDEX idx_location_overlap (location_ids_json);
然后在查询中改用 JSON_OVERLAPS(location_ids_json, ?) 进一步加速。
# mysql
# php
# laravel
# js
# json
# access
# ai
# red
# sql
# String
# 整型
# 字符串
# 循环
# 类型转换
# 对象
# location
# column
# 数据库
# 的是
# 退而求其次
# 两种
# 或其他
# 而非
# 哪种
# 可利用
# 是否存在
# 旧版
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?
千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】
网站制作软件有哪些,制图软件有哪些?
Laravel如何构建RESTful API_Laravel标准化API接口开发指南
html文件怎么打开证书错误_https协议的html打开提示不安全【指南】
如何快速打造个性化非模板自助建站?
桂林网站制作公司有哪些,桂林马拉松怎么报名?
公司网站制作需要多少钱,找人做公司网站需要多少钱?
使用豆包 AI 辅助进行简单网页 HTML 结构设计
Laravel如何配置任务调度?(Cron Job示例)
谷歌浏览器下载文件时中断怎么办 Google Chrome下载管理修复
Laravel Seeder怎么填充数据_Laravel数据库填充器的使用方法与技巧
android nfc常用标签读取总结
jQuery中的100个技巧汇总
历史网站制作软件,华为如何找回被删除的网站?
Laravel怎么做缓存_Laravel Cache系统提升应用速度的策略与技巧
Laravel怎么使用Session存储数据_Laravel会话管理与自定义驱动配置【详解】
如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?
如何利用DOS批处理实现定时关机操作详解
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全
Win11怎么修改DNS服务器 Win11设置DNS加速网络【指南】
猎豹浏览器开发者工具怎么打开 猎豹浏览器F12调试工具使用【前端必备】
Laravel中间件如何使用_Laravel自定义中间件实现权限控制
Laravel用户密码怎么加密_Laravel Hash门面使用教程
微信小程序制作网站有哪些,微信小程序需要做网站吗?
详解jQuery中的事件
Google浏览器为什么这么卡 Google浏览器提速优化设置步骤【方法】
如何在局域网内绑定自建网站域名?
阿里云高弹*务器配置方案|支持分布式架构与多节点部署
Laravel怎么配置S3云存储驱动_Laravel集成阿里云OSS或AWS S3存储桶【教程】
如何用花生壳三步快速搭建专属网站?
南京网站制作费用,南京远驱官方网站?
成都品牌网站制作公司,成都营业执照年报网上怎么办理?
百度浏览器网页无法复制文字怎么办 百度浏览器复制修复
Mybatis 中的insertOrUpdate操作
微信小程序 HTTPS报错整理常见问题及解决方案
iOS中将个别页面强制横屏其他页面竖屏
高防服务器:AI智能防御DDoS攻击与数据安全保障
rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted
Linux安全能力提升路径_长期防护思维说明【指导】
如何有效防御Web建站篡改攻击?
如何在阿里云通过域名搭建网站?
Swift中switch语句区间和元组模式匹配
Claude怎样写结构化提示词_Claude结构化提示词写法【教程】
免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?
武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?
JavaScript数据类型有哪些_如何准确判断一个变量的类型
Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】
Laravel如何与Pusher实现实时通信?(WebSocket示例)


) {
return $query->whereHas('shopAccess', function (Builder $q) use ($locations) {
$q->where(function ($sub) use ($locations) {
foreach ($locations as $location) {
// 将整数转为字符串,匹配 JSON 中的 "1"、"2" 等
$sub->orWhereJsonContains('location_ids', (string) $location);
}
});
});
}
return $query->whereNull('id');
}