You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Eloquent 查询:如何判断JSON字符串列skills与数组$skillArray是否存在交集(不使用属性转换)

解决Eloquent查询JSON字符串数组的任意匹配问题

嘿,这个场景我太熟悉了——把JSON数组存在字符串列里,普通的whereIn根本不管用,又不想用属性转换,咱们直接用数据库的JSON函数来搞定:

方法1:用MySQL 8.0.17+的JSON_OVERLAPS函数(最简洁)

如果你的MySQL版本够新,JSON_OVERLAPS是最方便的选择,它直接检查两个JSON数组是否有交集:

$skillArray = [9, 4];
// 注意:数据库里的skills是字符串元素,所以要把查询数组转成字符串数组再编码
$targetSkills = json_encode(array_map('strval', $skillArray));

$matchingEmployees = Employee::whereRaw('JSON_OVERLAPS(skills, ?)', [$targetSkills])->get();

为什么这么写?

  • JSON_OVERLAPS会自动解析skills列的JSON字符串,和你传入的目标JSON数组对比,只要有任意一个元素匹配就返回该行。
  • 必须把$skillArray的元素转成字符串,因为数据库里存的是"1"这种字符串类型,直接传数字会因为类型不匹配导致匹配失败。

方法2:兼容低版本MySQL(用JSON_TABLE拆分数组)

如果你的MySQL版本低于8.0.17,不支持JSON_OVERLAPS,可以用JSON_TABLE把JSON数组拆成临时表,再用whereExists子查询:

$skillArray = [9, 4];
$stringSkills = array_map('strval', $skillArray);

$matchingEmployees = Employee::whereExists(function ($query) use ($stringSkills) {
    $query->select(DB::raw(1))
          // 把skills列的JSON数组拆成每行一个skill的临时表
          ->from(DB::raw('JSON_TABLE(skills, "$[*]" COLUMNS(skill VARCHAR(255) PATH "$")) AS jt'))
          ->whereIn('jt.skill', $stringSkills);
})->get();

方法3:PostgreSQL环境下的写法

如果用的是PostgreSQL,用jsonb_array_elements_text来拆分数组:

$skillArray = [9, 4];
$stringSkills = array_map('strval', $skillArray);

$matchingEmployees = Employee::whereExists(function ($query) use ($stringSkills) {
    $query->select(DB::raw(1))
          ->from(DB::raw('jsonb_array_elements_text(skills::jsonb) AS skill'))
          ->whereIn('skill', $stringSkills);
})->get();

避坑提醒

  • JSON格式有效性:确保数据库里的skills列都是合法的JSON字符串,否则这些函数会抛出错误。
  • 类型严格匹配:一定要对齐数据库里的元素类型(比如数据库存字符串,查询就传字符串),不然会出现明明有值却匹配不到的情况。
  • 不推荐的REGEXP方法:如果实在没办法用JSON函数,也可以用正则,但要小心边界问题(比如"12"会被"1"误匹配),而且要转义正则特殊字符,仅作为最后备选。

内容的提问来源于stack exchange,提问作者Akshay K Nair

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 16:12:32