记录下最近 MySQL JSON 函数的使用

起因

在最近的一个项目实施过程中,由于原有数据存储的格式,需要从一大串的 JSONObject 或 JSONArray 中循环获取、或指定读取某一个 key 对应的值,通过原有的 concat + like 的组合效率已经远远不行了,这个时候想到了 MySQL 自5.7以来对JSON函数的支持,想着通过这样的方式来尝试下。

// 原有数据
    "key1": "value1",
    "key2": "value2",
    "key3": 3,
    "object1": {
        "object1Key1": "object1Value1",
        "object1Array": [
                "object1ArrayKey1": "object1ArrayValue1",
                "object1ArrayKey2": "object1ArrayValue2"
                "object1ArrayKey1": "object1ArrayValue3",
                "object1ArrayKey2": "object1ArrayValue4"
    "array1": [
            "array1Key1": "array1Value1",
            "array1Key2": 2
            "array1Key1": "array1Value3",
            "array1Key2": 4
}
原有数据大致是这样的,仍然需要注意的一点是存储在数据库的的数据类型是longtext,不是json格式。

接下来,我们通过 MySQL 的一系列函数+表,来获取我们所需要的一个数据。在此之前,我们先初始化下。

CREATE TABLE `test` (
  `str` varchar(600) COLLATE utf8mb4_general_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO test (str)
VALUES ('{"key1":"value1","key2":"value2","key3":3,"object1":{"object1Key1":"object1Value1","object1Array":[{"object1ArrayKey1":"object1ArrayValue1","object1ArrayKey2":"object1ArrayValue2"},{"object1ArrayKey1":"object1ArrayValue3","object1ArrayKey2":"object1ArrayValue4"}]},"array1":[{"array1Key1":"array1Value1","array1Key2":2},{"array1Key1":"array1Value3","array1Key2":4}]}');

1.获取 "key3",相对而言,这个是比较简单的。

select json_extract(str, '$.key3') key3 from test;

2.获取 "key3" 和 "object1ArrayKey1"

对于object1ArrayKey1而言,他是在"object1Array"数值下的对象的一个key,所以想要获取这样的一个值,我们需要遍历这个对象 这个时候就需要用到mysql本身自带的一张表来帮助我们实现。
select * from mysql.help_topic;
select json_extract(str, '$.key3')        key3,
       json_extract(json_unquote(json_extract(json_extract(str, '$.object1.object1Array'),
                                              concat('$[', help_topic.help_topic_id, ']'))),
                    '$.object1ArrayKey1') object1ArrayKey1
from test
         join mysql.help_topic on help_topic_id < json_length(json_extract(str, '$.object1.object1Array'));

3.获取"array1"下"array1Key1"值为'array1Value3'的对象的"array1Key2"的值

select json_extract(str,
                    replace(json_unquote(json_search(str, 'all', 'array1Value3', null, '$.array1[*].array1Key1')),
                            'array1Key1',
                            'array1Key2')) array1Key2
from test;
先用json_search函数后去"array1"下"array1Key1"值为'array1Value3'所处位置,把"array1Key1"替换为"array1Key2"再进行搜索;
还有点需要注意,json_search搜索出来的结果待引号,可以用json_unquote函数来取消引号,返回字符串;
另外使用json_search时,第三个参数,也就是待搜索值得是一个字符串。

在此基础上,我们还发现如果对于数组获取其对象属性时,数组在有限长度下,使用自己手写的序列表会比mysql.help_topic快,如下。

select 1 num
union
select 2 num