Laravel whereJsonContains用数组匹配JSON字段返回空集合的解决方法
解决Laravel whereJsonContains匹配JSON字符串值的类型与多值问题
看起来你遇到的问题核心是MySQL JSON函数的类型敏感性,以及对whereJsonContains处理数组参数的语义理解偏差,咱们一步步拆解解决:
为什么之前的写法无效?
- 类型不匹配:你的
payload->ProductCode->id存储的是字符串类型的"1",但你用数值1或者数值数组[1,2,3]去匹配时,MySQL的JSON_CONTAINS函数是严格类型匹配的,字符串和数值不会被视为相等,所以返回空集合。 - 数组参数的语义误解:当你给
whereJsonContains传数组时,它的语义是「匹配JSON路径对应的数组字段包含该数组的所有元素」,而你的id是单个字符串值,不是数组,所以这种写法从一开始就不符合场景。
正确的解决方案
1. 匹配单个值:确保类型一致
如果只是要匹配单个id,必须使用和数据库存储一致的字符串类型值:
// 这样就能正确返回目标记录 $myCollection = MyModel::whereJsonContains('payload->ProductCode->id', "1")->get();
2. 匹配多个值:结合JSON提取与whereIn
如果要匹配id是数组中任意一个字符串值的记录,推荐用whereIn配合原生JSON函数来实现,效率比循环orWhereJsonContains更高:
use Illuminate\Support\Facades\DB; // 注意数组元素是字符串,和数据库存储类型一致 $targetIds = ["1", "2", "3"]; $myCollection = MyModel::whereIn( // 提取并移除JSON字符串的引号,得到原始字符串值 DB::raw('JSON_UNQUOTE(JSON_EXTRACT(payload, "$.ProductCode.id"))'), $targetIds )->get();
3. 备选:循环添加orWhereJsonContains(适合小批量值)
如果你的目标数组元素不多,也可以用循环逐个添加orWhereJsonContains条件:
$targetIds = ["1", "2", "3"]; $query = MyModel::query(); foreach ($targetIds as $id) { $query->orWhereJsonContains('payload->ProductCode->id', $id); } $myCollection = $query->get();
额外提示
如果你的业务场景允许,也可以考虑在存入数据库时,将ProductCode->id存储为数值类型,这样后续匹配时就不用纠结类型问题,但这需要修改数据结构和写入逻辑,需要根据实际情况权衡。
内容的提问来源于stack exchange,提问作者mykoman
相关产品推荐
相关产品推荐

