
本文介绍在 Laravel 中高效查询 JSON 类型字段(如存储标签数组的 fields 列)是否包含给定值列表中至少一个元素的正确 Eloquent 写法,涵盖原生 SQL、JSON 函数及模型访问器等生产级解决方案。
本文介绍在 laravel 中高效查询 json 类型字段(如存储标签数组的 `fields` 列)是否包含给定值列表中**至少一个元素**的正确 eloquent 写法,涵盖原生 sql、json 函数及模型访问器等生产级解决方案。
在 Laravel 应用中,若用户表(users)的 fields 列以 JSON 格式存储字符串数组(如 ["fashion","commercial"]),而你需要检索“至少拥有 ["fashion", "food", "sport"] 中任一标签”的用户,不能直接使用 whereIn('fields', [...])——因为该写法会将整个 JSON 字符串(如 "["fashion","commercial"]")与目标字符串逐字匹配,而非进行 JSON 数组内元素级判断。
✅ 正确方案需借助数据库的 JSON 函数。以 MySQL 5.7+ 为例,推荐使用 JSON_CONTAINS() 配合 JSON_EXTRACT() 或更简洁的 ->> 操作符(MySQL 8.0+):
use Illuminate\Support\Facades\DB;
$targetTags = ['fashion', 'food', 'sport'];
$users = DB::table('users')
->where(function ($query) use ($targetTags) {
foreach ($targetTags as $tag) {
$query->orWhereRaw("JSON_CONTAINS(fields, ?)", ['"' . $tag . '"']);
}
})
->get();
更高效且兼容 Laravel 9+ 的写法(利用 whereJsonContains):
$users = User::where(function ($q) use ($targetTags) {
foreach ($targetTags as $tag) {
$q->orWhereJsonContains('fields', $tag);
}
})->get();
⚠️ 注意事项:
- whereJsonContains('fields', 'fashion') 要求 fields 是合法 JSON 数组(如 ["fashion","commercial"]),且会精确匹配字符串元素(区分大小写);
- 若 fields 列可能为 NULL 或非数组格式,建议添加约束:->whereNotNull('fields')->whereRaw('JSON_TYPE(fields) = "ARRAY";
- PostgreSQL 用户应改用 ?| 操作符:->whereRaw("fields ?| array[?]", [json_encode($targetTags)]);
- 频繁查询场景建议为 fields 列添加生成列 + 索引(MySQL)或 GIN 索引(PostgreSQL)以提升性能。
? 进阶提示:可在 User 模型中定义访问器简化逻辑:
// app/Models/User.php
protected $casts = [
'fields' => 'array',
];
// 查询时仍推荐用 whereJsonContains,访问器仅用于读取后处理
综上,避免在 PHP 层遍历过滤(如 array_intersect),优先交由数据库完成 JSON 数组的语义化查询——既保障性能,又确保结果准确性与事务一致性。











