본문 바로가기

MariaDB, MySQL

MySQL 8.0 JSON

JSON

["a"] - JSON ARRAY

["a","b"] - JSON ARRAY ( Ordered collection of values )

["a", {"b": 20}] - JSON OBJECT ( Having key, value, Unordered set of name/value pairs )

["a", {"b": [20, 30]}]

 

JSON column is limited to the value of the max_allowed_packet

You can manipulate the size of JSON using JSON_STORAGE_SIZE() function

MySQL handles strings used in JSON context using the utf8mb4 character set.

Partial Updates of JSON Values

In MySQL 8.0 a partial, in-place update of a JSON column.

  • The column being updated was declared as JSON.

  • Can be partial updated using JSON_SET(), JSON_REPLACE(), or JSON_REMOVE()

  • The input column and target column must be the same column

  • Not for partial updates UPDATE ... SET A = JSON_SET ( B, .. )

  • Not for adding any new elements to the parent object or array.

  • The new value cannot be any larger than the old one.

Functions

ORACLE supports many JSON functions.

Most of them related to create/modify functions as SELECT queries.

  • JSON_EXTRACT - Most used, extract specific value

  • JSON_PRETTY() - Print JSON with format

JSON Function Reference

Test cases

mysql> desc products;
+-------+---------+------+-----+---------+----------------+
| Field | Type    | Null | Key | Default | Extra          |
+-------+---------+------+-----+---------+----------------+
| id    | int(11) | NO   | PRI | NULL    | auto_increment |
| data  | json    | YES  |     | NULL    |                |
+-------+---------+------+-----+---------+----------------+

Insert

mysql> insert into products(data) values('{"Foods":[{"Food":"Bread","Color":"White"},{"Food":"Noodle","Color":"Yellow"}]}');
Query OK, 1 row affected (0.00 sec)

mysql> insert into products(data) values('{"Foods":[{"Food":"Lagsana"},{"Food":"Ramen"}]}');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

SELECT

SELECT LIST

mysql> select * from products;
+----+-----------------------------------------------------------------------------------------+
| id | data                                                                                    |
+----+-----------------------------------------------------------------------------------------+
|  1 | ["Food", "Color"]                                                                       |
|  2 | {"Foods": [{"Food": "Bread", "Color": "White"}, {"Food": "Noodle", "Color": "Yellow"}]} |
|  3 | {"Foods": [{"Food": "Lagsana"}, {"Food": "Ramen"}]}                                     |
+----+-----------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)

mysql> select id, data->"$.Foods[0]" from products;
+----+-------------------------------------+
| id | data->"$.Foods[0]"                  |
+----+-------------------------------------+
|  1 | NULL                                |
|  2 | {"Food": "Bread", "Color": "White"} |
|  3 | {"Food": "Lagsana"}                 |
+----+-------------------------------------+
3 rows in set (0.00 sec)

mysql> select id, json_extract(data, "$.Foods[0]") from products;
+----+-------------------------------------+
| id | json_extract(data, "$.Foods[0]")    |
+----+-------------------------------------+
|  1 | NULL                                |
|  2 | {"Food": "Bread", "Color": "White"} |
|  3 | {"Food": "Lagsana"}                 |
+----+-------------------------------------+
3 rows in set (0.00 sec)

SELECT WHERE

To select specific rows following JSON_FUNCTIONS can be used.

  • JSON_CONTAINS( target, candidate[, path])

  • JSON_EXTRACT( json_doc, path[, path] ...)

  • column->path : An alias for the JSON_EXTRACT

  • JSON_KEYS(json_doc[, path])

  • MEMBER_OF

But to use condition efficiently from JSON data type, consider creating index on generated columns.

mysql> select id, json_extract(data, "$.Foods[0]") from products
    -> where data->"$.Foods[0].Color" = 'White';
+----+-------------------------------------+
| id | json_extract(data, "$.Foods[0]")    |
+----+-------------------------------------+
|  2 | {"Food": "Bread", "Color": "White"} |
+----+-------------------------------------+
1 row in set (0.00 sec)


mysql> select id, data from products
    -> where json_contains_path(data, 'all','$.Foods') = 1;
+----+-----------------------------------------------------------------------------------------+
| id | data                                                                                    |
+----+-----------------------------------------------------------------------------------------+
|  2 | {"Foods": [{"Food": "Bread", "Color": "White"}, {"Food": "Noodle", "Color": "Yellow"}]} |
|  3 | {"Foods": [{"Food": "Lagsana"}, {"Food": "Ramen"}]}                                     |
+----+-----------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

UPDATE, DELETE

Same as normal DML.

For partial updates, you have to use JSON_SET(), JSON_REPLACE(), or JSON_REMOVE().

JSON functions that sound like DML operations, not related DML.

( Such as JSON_ARRAY_APPEND, JSON_REMOVE ... )

mysql> select id, data from products where id = 1;
+----+-------------------+
| id | data              |
+----+-------------------+
|  1 | ["Food", "Color"] |
+----+-------------------+
1 row in set (0.00 sec)

mysql> update products
    -> set data = '["Food", "Color", "Price"]'
    -> where id = 1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select id, data from products where id = 1;
+----+----------------------------+
| id | data                       |
+----+----------------------------+
|  1 | ["Food", "Color", "Price"] |
+----+----------------------------+
1 row in set (0.00 sec)

 

INDEXING on JSON

MySQL 8.0 Supports for indexing on generated columns.

 

mysql> Explain
    -> select id, data->>"$.Foods[0].Color[0]" from products
    -> where data->"$.Foods[0].Color" = 'White';
+----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table    | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | products | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | Using where |
+----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
mysql> alter table products add column color varchar(20) generated always as (data->>"$.Foods[0].Color[0]") stored;
Query OK, 3 rows affected (0.03 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> create index ix1_products on products (color);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> Explain
    -> select id, data->>"$.Foods[0].Color[0]" from products
    -> where data->>"$.Foods[0].Color[0]" = 'White';
+----+-------------+----------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
| id | select_type | table    | partitions | type | possible_keys | key          | key_len | ref   | rows | filtered | Extra |
+----+-------------+----------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | products | NULL       | ref  | ix1_products  | ix1_products | 83      | const |    1 |   100.00 | NULL  |
+----+-------------+----------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> show warnings;
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                              |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `test`.`products`.`id` AS `id`,json_unquote(json_extract(`test`.`products`.`data`,'$.Foods[0].Color[0]')) AS `data->>"$.Foods[0].Color[0]"` from `test`.`products` where (`test`.`products`.`color` = 'White') |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)