当前位置:网站首页>MySQL学习笔记:JSON嵌套数组查询

MySQL学习笔记:JSON嵌套数组查询

2022-06-11 02:40:00 山鬼谣me

环境

MySQL 5.7

先假设数据

简单JSON串就不说了,很简单,来个复杂点的:

[
    {
    
        "type":[
            {
    
                "code":"xmf",
                "name":"小蜜蜂"
            }
        ],
        "cities":[
            {
    
                "code":"1",
                "name":"上海"
            }
        ],
        "oType":[
            {
    
                "code":"order",
                "name":"单子"
            }
        ],
        "p":[
            {
    
                "code":"110",
                "name":"快点送"
            }
        ]
    }
]

在MySQL数据库中,它长这个样子:

在这里插入图片描述
上图只是为了说明,上面整个JSON串在数据库里对应的字段是detail

网上很多都是先{......}对象,然后再嵌套数组,但是我的数据是[......],即:先是个数组,然后嵌套对象,然后再嵌套数组。

这种情况下,该如何查询呢?

MySQL 嵌套数组查询方法

现在想查询,JSON串中城市字段是上海的。
正确的SQL:

SELECT * 
from `template_yutao` 
where json_contains( `detail`, json_object('cities', json_array(json_object('name', '上海'))))

思路:json_contains作用:是否包含子文档。那我们就构造一个子文档出来,然后输入进去查询即可。

我曾尝试使用提取方法,想简写上面的SQL:

-- 想着先提取cities这一层,再进行查询
-- 很遗憾,在json_contains里面不能写 * 或 **
SELECT * from `alsc_cs_minos_template_biz` 
where json_contains( `detail`, json_object('name', '上海'), '$[*].cities')
-- 之后又改写成 下面这个可以成功,但是$[0]等于限制成了数组的第一个,不方便以后扩展。
-- 研究了半天,没有研究出提取一层的方法;不过上面的查询已经够用了。
--其实因为json_contains里面不能写 * 或 **,就已经说明它其实不能提取,只能明确指定提取。
SELECT * from `alsc_cs_minos_template_biz` 
where json_contains( `detail`, json_object('name', '上海'), '$[0].cities')

说明:
这里需要说下,上面的json查询,和MongoDB相似,但是却没有MongoDB强大,MongoDB的话,只需要这么查:

SELECT * 
from `template_yutao` 
where detail.cities.name = '上海' -- 这不是标准的MongoDB写法,只是想表达大概的意思。

-- MongoDB标准写法
db.template_yutao.find('$.detail.cities.name', '上海'); 

Mybatis 结合

假设我们利用Mybatis-Generator生成Mapper文件中的代码是:criteria 类的形式。

Mapper.xml形如:

<if test="_parameter != null">
  <where>
    <foreach collection="oredCriteria" item="criteria" separator="or">
      <if test="criteria.valid">
        <trim prefix="(" prefixOverrides="and" suffix=")">
          <foreach collection="criteria.criteria" item="criterion">
            <choose>
              <when test="criterion.noValue">
                and ${criterion.condition}
              </when>
              <when test="criterion.singleValue">
                and t.${criterion.condition} #{criterion.value}
              </when>
              <when test="criterion.betweenValue">
                and t.${criterion.condition} #{criterion.value} and #{criterion.secondValue}
              </when>
              <when test="criterion.listValue">
                and t.${criterion.condition}
                <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
                  #{listItem}
                </foreach>
              </when>
            </choose>
          </foreach>
        </trim>
      </if>
    </foreach>
  </where>
</if>
<if test="orderByClause != null">
  order by ${@[email protected](orderByClause)}
</if>
<if test="page">
  limit #{pageIndex},#{pageSize}
</if>

相关类XXXParam类,形如下面的形式:

protected abstract static class AbstractGeneratedCriteria {
    
      protected List<Criterion> criteria;

      protected AbstractGeneratedCriteria() {
    
          super();
          criteria = new ArrayList<Criterion>();
      }

      public boolean isValid() {
    
          return criteria.size() > 0;
      }

      public List<Criterion> getAllCriteria() {
    
          return criteria;
      }

      public List<Criterion> getCriteria() {
    
          return criteria;
      }

      protected void addCriterion(String condition) {
    
          if (condition == null) {
    
              throw new RuntimeException("Value for condition cannot be null");
          }
          criteria.add(new Criterion(condition));
      }

      protected void addCriterion(String condition, Object value, String property) {
    
          if (value == null) {
    
              throw new RuntimeException("Value for " + property + " cannot be null");
          }
          criteria.add(new Criterion(condition, value));
      }

      protected void addCriterion(String condition, Object value1, Object value2, String property) {
    
          if (value1 == null || value2 == null) {
    
              throw new RuntimeException("Between values for " + property + " cannot be null");
          }
          criteria.add(new Criterion(condition, value1, value2));
      }

      public Criteria andIdIsNull() {
    
          addCriterion("id is null");
          return (Criteria) this;
      }

      public Criteria andIdIsNotNull() {
    
          addCriterion("id is not null");
          return (Criteria) this;
      }

那么这时,代码该如何编写呢?

我的做法就是在里面添加一个如下方法:

/** * * @param cityList * @return */
 public Criteria andCityCodeJson(List<String> cityList) {
    
     if (cityList == null || cityList.size() == 0) {
    
         throw new RuntimeException("Value for cityList cannot be null");
     }
     StringBuilder cityStr = new StringBuilder();
     int size = cityList.size();
     for (int i = 0; i < size; i++) {
    
         if (i == size - 1) {
    
             cityStr.append("json_object('code', '").append(cityList.get(i)).append("')");
         } else {
    
             cityStr.append("json_object('code', '").append(cityList.get(i)).append("')").append(",");
         }
     }
     addCriterion("json_contains(detail, json_object('city', json_array(" + cityStr +")))");
     return (Criteria) this;
 }

MySQL JSON方法说明

以下是简单说明,言简意赅的那种,详情可以参考官网:
12.18.3 Functions That Search JSON Values

json_contains

JSON_CONTAINS(json_doc, val[, path]) 是否包含子文档.

JSON_EXTRACT

JSON_EXTRACT(json_doc, path[, path] …) 获得doc中某个或多个节点的值。

参考地址

12.18.3 Functions That Search JSON Values

MySQL 5.7 JSON 数据类型的使用

mysql根据json字段的内容检索查询数据

原网站

版权声明
本文为[山鬼谣me]所创,转载请带上原文链接,感谢
https://blog.csdn.net/u013066244/article/details/125166872