You are on page 1of 18

From the desk of B. J.

Ferro

Versión libre del artículo “How To Work with JSON in MySQL” de


Noman Ur Rehman disponible en:
https://www.digitalocean.com/community/tutorials/working-with-json-
in-mysql

Introducción
MySQL y otros manejadores incorporan el tipo de datos JSON para
atributos o campos de sus tablas. Para eso, incluyen funciones que
permiten manipular esos atributos con “mayor” flexibilidad y con
flexibilidad en su esquema.
En el artículo se describe una base de datos sencilla compuesta por
tres tablas y utilizando un atributo de tipo JSON en una de sus
tablas.

Creación de la base de datos


CREATE DATABASE IF NOT EXISTS `e_store`
DEFAULT CHARACTER SET utf8
DEFAULT COLLATE utf8_general_ci;
SET default_storage_engine = INNODB;

Creación de las tablas de la base de datos e_store


Tabla brands
CREATE TABLE `e_store`.`brands`(
`id` INT UNSIGNED NOT NULL auto_increment ,
`name` VARCHAR(250) NOT NULL ,
PRIMARY KEY(`id`)
);

Tabla categories
CREATE TABLE `e_store`.`categories`(
`id` INT UNSIGNED NOT NULL auto_increment ,
`name` VARCHAR(250) NOT NULL ,
PRIMARY KEY(`id`)
);
From the desk of B. J. Ferro

Tabla products
CREATE TABLE `e_store`.`products`(
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(250) NOT NULL ,
`brand_id` INT UNSIGNED NOT NULL ,
`category_id` INT UNSIGNED NOT NULL ,

`attributes` JSON NOT NULL ,


PRIMARY KEY(`id`) ,
INDEX `CATEGORY_ID`(`category_id` ASC) ,
INDEX `BRAND_ID`(`brand_id` ASC) ,
CONSTRAINT `brand_id` FOREIGN KEY(`brand_id`) REFERENCES
`e_store`.`brands`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE ,
CONSTRAINT `category_id` FOREIGN KEY(`category_id`) REFERENCES
`e_store`.`categories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE
);

El esquema de la base de datos


From the desk of B. J. Ferro

Inserción de datos en las tablas brands y categories


INSERT INTO `e_store`.`brands`(`name`) VALUES ('Samsung');
INSERT INTO `e_store`.`brands`(`name`) VALUES ('Nokia');
INSERT INTO `e_store`.`brands`(`name`) VALUES ('Canon');

INSERT INTO `e_store`.`categories`(`name`) VALUES ('Television');


INSERT INTO `e_store`.`categories`(`name`) VALUES ('Mobile Phone');
INSERT INTO `e_store`.`categories`(`name`) VALUES ('Camera');

Inserción de datos en la tabla products


Observemos que el campo attributes se ha declarado de tipo JSON. La
forma de expresarlo es similar a la de expresar una cadena de
caracteres o varchar, pero no es de ese tipo; su tipo es JSON.

INSERT INTO `e_store`.`products`(


`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Prime' ,
'1' ,
'1' ,
'{"screen": "50 inch", "resolution": "2048 x 1152 pixels",
"ports": {"hdmi": 1, "usb": 3}, "speakers": {"left": "10 watt",
"right": "10 watt"}}'
);
From the desk of B. J. Ferro

INSERT INTO `e_store`.`products`(


`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Octoview' ,
'1' ,
'1' ,
'{"screen": "40 inch", "resolution": "1920 x 1080 pixels",
"ports": {"hdmi": 1, "usb": 2}, "speakers": {"left": "10 watt",
"right": "10 watt"}}'
);

INSERT INTO `e_store`.`products`(


`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Dreamer' ,
'1' ,
'1' ,
'{"screen": "30 inch", "resolution": "1600 x 900 pixles",
"ports": {"hdmi": 1, "usb": 1}, "speakers": {"left": "10 watt",
"right": "10 watt"}}'
);
From the desk of B. J. Ferro

INSERT INTO `e_store`.`products`(


`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Bravia' ,
'1' ,
'1' ,
'{"screen": "25 inch", "resolution": "1366 x 768 pixels",
"ports": {"hdmi": 1, "usb": 0}, "speakers": {"left": "5 watt",
"right": "5 watt"}}'
);

INSERT INTO `e_store`.`products`(


`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Proton' ,
'1' ,
'1' ,
'{"screen": "20 inch", "resolution": "1280 x 720 pixels",
"ports": {"hdmi": 0, "usb": 0}, "speakers": {"left": "5 watt",
"right": "5 watt"}}'
);
From the desk of B. J. Ferro

Observemos los objetos JSON, valores del campo attributes. Tomemos


uno de ellos y veamos que el campo speakers es un objeto embebido
con sus respectivos campos.

{"screen": "50 inch", "resolution": "2048 x 1152 pixels", "ports":


{"hdmi": 1, "usb": 3}, "speakers": {"left": "10 watt", "right": "10
watt"}}

Utilización de la función JSON_OBJECT para la creación de


objetos JSON
Podemos utilizar la función JSON_OBJECT que ofrece MySQL para crear
los objetos JSON. Noten que la sintaxis es diferente; la función
acepta pares llave, valor para cada uno de las tuplas del objeto
JSON.
En las inserciones que vienen a continuación, se está utilizando
también la función JSON_ARRAY para declarar campos de tipo arreglo.
Nótese también que ahora estamos insertando otro tipo de producto
(teléfonos móviles) en la tabla products, con esquema diferente a
los productos (televisores) insertados con anterioridad.

INSERT INTO `e_store`.`products`(


`name` , `brand_id` , `category_id` , `attributes`
)
VALUES(
'Desire' , '2' , '2' ,
JSON_OBJECT(
"network" , JSON_ARRAY("GSM" , "CDMA" , "HSPA" , "EVDO")
,
"body" , "5.11 x 2.59 x 0.46 inches" ,
"weight" , "143 grams" ,
"sim" , "Micro-SIM" ,
"display" , "4.5 inches" ,
"resolution" , "720 x 1280 pixels" ,
"os" , "Android Jellybean v4.3"
)
);
From the desk of B. J. Ferro

INSERT INTO `e_store`.`products`(


`name` , `brand_id` , `category_id` , `attributes`
)
VALUES(
'Passion' , '2' , '2' ,
JSON_OBJECT(
"network" , JSON_ARRAY("GSM" , "CDMA" , "HSPA") ,
"body" , "6.11 x 3.59 x 0.46 inches" ,
"weight" , "145 grams" ,
"sim" , "Micro-SIM" ,
"display" , "4.5 inches" ,
"resolution" , "720 x 1280 pixels" ,
"os" , "Android Jellybean v4.3"
)
);

INSERT INTO `e_store`.`products`(


`name` , `brand_id` , `category_id` , `attributes`
)
VALUES(
'Emotion' , '2' , '2' ,
JSON_OBJECT(
"network" , JSON_ARRAY("GSM" , "CDMA" , "EVDO") ,
"body" , "5.50 x 2.50 x 0.50 inches" ,
"weight" , "125 grams" ,
"sim" , "Micro-SIM" ,
"display" , "5.00 inches" ,
"resolution" , "720 x 1280 pixels" ,
"os" , "Android KitKat v4.3"
From the desk of B. J. Ferro

)
);

INSERT INTO `e_store`.`products`(


`name` , `brand_id` , `category_id` , `attributes`
)
VALUES(
'Sensation' , '2' , '2' ,
JSON_OBJECT(
"network" , JSON_ARRAY("GSM" , "HSPA" , "EVDO") ,
"body" , "4.00 x 2.00 x 0.75 inches" ,
"weight" , "150 grams" ,
"sim" , "Micro-SIM" ,
"display" , "3.5 inches" ,
"resolution" , "720 x 1280 pixels" ,
"os" , "Android Lollipop v4.3"
)
);

INSERT INTO `e_store`.`products`(


`name` , `brand_id` , `category_id` , `attributes`
)
VALUES(
'Joy' , '2' , '2' ,
JSON_OBJECT(
"network" , JSON_ARRAY("CDMA" , "HSPA" , "EVDO") ,
"body" , "7.00 x 3.50 x 0.25 inches" ,
"weight" , "250 grams" ,
"sim" , "Micro-SIM" ,
From the desk of B. J. Ferro

"display" , "6.5 inches" ,


"resolution" , "1920 x 1080 pixels" ,
"os" , "Android Marshmallow v4.3"
)
);
From the desk of B. J. Ferro

Utilización de la función JSON_MERGE_PRESERVE.


Utilizamos la función JSON_MERGE_PRESERVE para crear un objeto JSON
agregado a partir de varios objetos JSON. En las inserciones
siguientes se está añadiendo un nuevo tipo de producto a la tabla
products; diferentes tipos de cámaras.

INSERT INTO `e_store`.`products`(


`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Explorer' ,
'3' ,
'3' ,
JSON_MERGE_PRESERVE(
'{"sensor_type": "CMOS"}' ,
'{"processor": "Digic DV III"}' ,
'{"scanning_system": "progressive"}' ,
'{"mount_type": "PL"}' ,
'{"monitor_type": "LCD"}'
)
);
From the desk of B. J. Ferro

INSERT INTO `e_store`.`products`(


`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Runner' ,
'3' ,
'3' ,
JSON_MERGE_PRESERVE(
JSON_OBJECT("sensor_type" , "CMOS") ,
JSON_OBJECT("processor" , "Digic DV II") ,
JSON_OBJECT("scanning_system" , "progressive") ,
JSON_OBJECT("mount_type" , "PL") ,
JSON_OBJECT("monitor_type" , "LED")
)
);

INSERT INTO `e_store`.`products`(


`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Traveler' ,
'3' ,
'3' ,
JSON_MERGE_PRESERVE(
From the desk of B. J. Ferro

JSON_OBJECT("sensor_type" , "CMOS") ,
'{"processor": "Digic DV II"}' ,
'{"scanning_system": "progressive"}' ,
'{"mount_type": "PL"}' ,
'{"monitor_type": "LCD"}'
)
);

INSERT INTO `e_store`.`products`(


`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Walker' ,
'3' ,
'3' ,
JSON_MERGE_PRESERVE(
'{"sensor_type": "CMOS"}' ,
'{"processor": "Digic DV I"}' ,
'{"scanning_system": "progressive"}' ,
'{"mount_type": "PL"}' ,
'{"monitor_type": "LED"}'
)
);
From the desk of B. J. Ferro

INSERT INTO `e_store`.`products`(


`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Jumper' ,
'3' ,
'3' ,
JSON_MERGE_PRESERVE(
'{"sensor_type": "CMOS"}' ,
'{"processor": "Digic DV I"}' ,
'{"scanning_system": "progressive"}' ,
'{"mount_type": "PL"}' ,
'{"monitor_type": "LCD"}'
)
);
From the desk of B. J. Ferro

Procesamiento de los datos contenidos en los objetos JSON de


la tabla products
Para procesar campos JSON tenemos que usar los “path Expressions”
(¿expresiones de ruta?).
La expresión de ruta es una cadena que contiene una expresión de
ruta JSON válida descrita en WL#7909. Se basan en el proyecto
DocStore de Facebook, que tiene una forma intuitiva de acceder a
JSON en SQL. Usaron una notación de puntos, pero en MySQL se utiliza
la notación de flecha (->) como separador para evitar ambigüedades.

Un ejemplo sencillo. MySQL :: Inline JSON Path Expressions in MySQL 5.7

Creemos la siguiente tabla en la base de datos e_store (después si


queremos la borramos).

CREATE TABLE employees (data JSON);

Insertemos dos registros:

INSERT INTO employees VALUES ('{"id": 1, "name": "Pedro"}');


INSERT INTO employees VALUES ('{"id": 2, "name": "Juan"}');

Y ahora realizamos una consulta:


SELECT * FROM employees WHERE data->'$.id'= 2;

La expresión data->'$.id' es azúcar sintáctica para


json_extract(data, '$.id'). Debido a eso, se trata como si se
hubiera especificado json_extract() en su lugar.
From the desk of B. J. Ferro

Sigamos con nuestros ejemplos para la base de datos e_store.


Consulta: Buscar todos los televisores que tienen al menos un puerto
USB y un puerto HDMI.

El primer argumento de la función JSON_EXTRACT es el JSON para


aplicar la expresión de ruta a la columna attributes.
El símbolo $ tokeniza el objeto con el que trabajar. Las expresiones
de ruta $.ports.usb y $.ports.hdmi se traducen como "tomar la clave
usb debajo de los puertos" y "tomar la clave hdmi debajo de los
puertos" respectivamente.
Noten también la notación de flecha que hemos utilizado en la
expresión de ruta para la proyección de determinados campos del
objeto JSON.
Realicemos la misma consulta pero utilizando la notación de flecha
para la selección en la cláusula WHERE.
From the desk of B. J. Ferro

Actualizar datos de los objetos JSON


Para la actualización de datos de los campos de los objetos JSON,
también usamos las expresiones de ruta y tres funciones que nos
brinda el servidor: JSON_INSERT, JSON_REPLACE, y JSON_SET.
Query: Añadimos una nueva llave chipset con el valor “Qualcomm” a
todos los teléfonos móviles que se describen en la tabla products.

UPDATE `e_store`.`products`
SET `attributes` = JSON_INSERT(`attributes`,'$.chipset' ,'Qualcomm')
WHERE `category_id` = 2;

Nos equivocamos! Nos dijeron que el chipser es “Qualcomm


Snapsdragon”. Utilicemos la función JSON_REPLACe para esa
corrección:
UPDATE `e_store`.`products`
SET `attributes` = JSON_REPLACE(`attributes` ,'$.chipset' ,
'Qualcomm Snapdragon') WHERE `category_id` = 2;
From the desk of B. J. Ferro

Otra actualización: Añadamos un nuevo campo al objeto JSON que


describe a los televisores. Que sea el atributo body_color con un
valor de red.
UPDATE `e_store`.`products`
SET `attributes` = JSON_SET(`attributes` ,'$.body_color' ,'red')
WHERE `category_id` = 1;

Eliminación de campos de un campo JSON


Para la eliminación de campos de un campo JSON utilizamos DELETE y
la función del servidor JSON_REMOVE
Query. Eliminemos el campo mount_type de la cámara de tipo Walker
que aparece en la tabla products.
UPDATE `e_store`.`products`
SET `attributes` = JSON_REMOVE(`attributes` , '$.mount_type')
WHERE `category_id` = 3 AND name =’Walker’;
From the desk of B. J. Ferro

Podemos usar DELETE y combinar el predicado con JSON_EXTRACT.


Eliminemos todos los celulares Android que tienen como os a
Jellybeans.

DELETE FROM `e_store`.`products`


WHERE `category_id` = 2
AND JSON_EXTRACT(`attributes` , '$.os') LIKE '%Jellybean%';

Conclusiones

Recomiendo revisar el API de JSON que brindan los servidores de bases de datos relacionales.

You might also like