JSON_LENGTH
La función JSON_LENGTH cuenta el número de elementos en un valor JSON. Si el valor es un array, devuelve la cantidad de elementos que contiene. Si es un objeto, devuelve la cantidad de pares clave-valor. Si es un valor escalar (cadena, número, booleano o null), devuelve 1. Esta función es fundamental para analizar la estructura de tus datos JSON, filtrar registros según el tamaño de sus arrays, y verificar que los documentos contengan la cantidad esperada de campos.
Sintaxis
JSON_LENGTH(json_doc [, ruta])El primer argumento es el documento JSON a evaluar. El segundo argumento es opcional y especifica una ruta dentro del documento. Cuando proporcionas una ruta, JSON_LENGTH mide el elemento que se encuentra en esa ubicación en lugar del documento raíz. Si la ruta no existe en el documento, la función devuelve NULL.
JSON_LENGTH(json_doc)
JSON_LENGTH(json_doc, '$.ruta')Comportamiento básico
Con un array, JSON_LENGTH cuenta sus elementos:
SELECT JSON_LENGTH('[10, 20, 30, 40, 50]') AS longitud;| longitud |
|---|
| 5 |
Con un objeto, cuenta los pares clave-valor:
SELECT JSON_LENGTH('{"nombre": "iPhone", "precio": 1299, "color": "negro"}') AS longitud;| longitud |
|---|
| 3 |
Un array o un objeto vacíos tienen longitud cero:
SELECT
JSON_LENGTH('[]') AS array_vacio,
JSON_LENGTH('{}') AS objeto_vacio;| array_vacio | objeto_vacio |
|---|---|
| 0 | 0 |
Los valores escalares siempre tienen longitud 1, independientemente de su contenido:
SELECT
JSON_LENGTH('"una cadena larga de texto"') AS cadena,
JSON_LENGTH('42') AS numero,
JSON_LENGTH('true') AS booleano,
JSON_LENGTH('null') AS nulo;| cadena | numero | booleano | nulo |
|---|---|---|---|
| 1 | 1 | 1 | 1 |
Cuando usas el segundo argumento para especificar una ruta, la función mide el elemento en esa ubicación:
SELECT
JSON_LENGTH('{"tags": ["a", "b", "c"], "specs": {"ram": 8, "cpu": "A17"}}', '$.tags') AS len_tags,
JSON_LENGTH('{"tags": ["a", "b", "c"], "specs": {"ram": 8, "cpu": "A17"}}', '$.specs') AS len_specs;| len_tags | len_specs |
|---|---|
| 3 | 2 |
Caso práctico: análisis de catálogo de productos
Imagina un catálogo donde cada producto tiene arrays de imágenes, etiquetas y un objeto de especificaciones con un número variable de campos:
CREATE TABLE productos (
id INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100),
datos JSON
);
INSERT INTO productos (nombre, datos) VALUES
('iPhone 15 Pro',
'{"imágenes": ["frontal.jpg", "trasera.jpg", "lateral.jpg", "detalle.jpg"], "etiquetas": ["smartphone", "apple", "5g", "premium"], "specs": {"ram": 8, "almacenamiento": 256, "pantalla": 6.1, "batería": 3274, "cámara": "48MP"}}'),
('Funda silicona',
'{"imágenes": ["principal.jpg"], "etiquetas": ["accesorio"], "specs": {"material": "silicona", "compatible": "iPhone 15"}}'),
('Samsung Galaxy S24',
'{"imágenes": ["frontal.jpg", "trasera.jpg"], "etiquetas": ["smartphone", "samsung", "5g"], "specs": {"ram": 12, "almacenamiento": 256, "pantalla": 6.2}}'),
('MacBook Air M3',
'{"imágenes": ["abierto.jpg", "cerrado.jpg", "perfil.jpg"], "etiquetas": ["portátil", "apple", "ultrabook"], "specs": {"ram": 16, "almacenamiento": 512, "pantalla": 13.6, "batería": 52.6, "peso": 1.24, "cpu": "M3"}}');Para ver cuántas imágenes, etiquetas y especificaciones tiene cada producto:
SELECT
nombre,
JSON_LENGTH(datos, '$.imágenes') AS num_imágenes,
JSON_LENGTH(datos, '$.etiquetas') AS num_etiquetas,
JSON_LENGTH(datos, '$.specs') AS num_specs
FROM productos;| nombre | num_imágenes | num_etiquetas | num_specs |
|---|---|---|---|
| iPhone 15 Pro | 4 | 4 | 5 |
| Funda silicona | 1 | 1 | 2 |
| Samsung Galaxy S24 | 2 | 3 | 3 |
| MacBook Air M3 | 3 | 3 | 6 |
Para encontrar productos que necesitan más fotografías (menos de 3 imágenes):
SELECT nombre, JSON_LENGTH(datos, '$.imágenes') AS imágenes
FROM productos
WHERE JSON_LENGTH(datos, '$.imágenes') < 3;| nombre | imágenes |
|---|---|
| Funda silicona | 1 |
| Samsung Galaxy S24 | 2 |
Caso práctico: control de calidad de datos
JSON_LENGTH es muy útil para establecer umbrales de calidad. Puedes categorizar los productos según la completitud de su información:
SELECT
nombre,
JSON_LENGTH(datos, '$.specs') AS campos_specs,
CASE
WHEN JSON_LENGTH(datos, '$.specs') >= 5 THEN 'Completo'
WHEN JSON_LENGTH(datos, '$.specs') >= 3 THEN 'Parcial'
ELSE 'Mínimo'
END AS nivel_detalle
FROM productos;| nombre | campos_specs | nivel_detalle |
|---|---|---|
| iPhone 15 Pro | 5 | Completo |
| Funda silicona | 2 | Mínimo |
| Samsung Galaxy S24 | 3 | Parcial |
| MacBook Air M3 | 6 | Completo |
También puedes usarla para detectar registros con arrays vacíos que podrían indicar datos incompletos:
SELECT nombre
FROM productos
WHERE JSON_LENGTH(datos, '$.etiquetas') = 0
OR JSON_LENGTH(datos, '$.imágenes') = 0;Esta consulta encontraría productos sin etiquetas o sin imágenes, lo cual podría ser un problema para la visualización en una tienda en línea.
Caso práctico: paginación y límites en arrays JSON
Cuando almacenas listas de elementos en columnas JSON, JSON_LENGTH te permite implementar verificaciones de límite. Considera una tabla de listas de deseos:
CREATE TABLE listas_deseos (
id INT PRIMARY KEY AUTO_INCREMENT,
usuario VARCHAR(100),
productos JSON DEFAULT ('[]')
);
INSERT INTO listas_deseos (usuario, productos) VALUES
('María García', '["iPhone 15 Pro", "AirPods Pro", "Apple Watch", "iPad Air", "MacBook Air"]'),
('Carlos López', '["Samsung Galaxy S24", "Galaxy Buds"]'),
('Ana Martínez', '["Kindle Paperwhite"]');Para mostrar un resumen de las listas con un conteo:
SELECT
usuario,
JSON_LENGTH(productos) AS items_en_lista,
CASE
WHEN JSON_LENGTH(productos) >= 5 THEN 'Lista llena (máx. 5)'
ELSE CONCAT('Puede añadir ', 5 - JSON_LENGTH(productos), ' más')
END AS estado
FROM listas_deseos;| usuario | items_en_lista | estado |
|---|---|---|
| María García | 5 | Lista llena (máx. 5) |
| Carlos López | 2 | Puede añadir 3 más |
| Ana Martínez | 1 | Puede añadir 4 más |
Para verificar antes de insertar un elemento si la lista ya alcanzó su límite:
SELECT
usuario,
IF(JSON_LENGTH(productos) < 5, 'Permitir', 'Rechazar') AS accion
FROM listas_deseos
WHERE usuario = 'María García';| usuario | accion |
|---|---|
| María García | Rechazar |
Manejo de NULL
Cuando el documento JSON es NULL, la función devuelve NULL:
SELECT JSON_LENGTH(NULL) AS resultado;| resultado |
|---|
| NULL |
Cuando la ruta especificada no existe en el documento, también devuelve NULL:
SELECT JSON_LENGTH('{"nombre": "Test"}', '$.inexistente') AS resultado;| resultado |
|---|
| NULL |
Este comportamiento es importante tenerlo en cuenta cuando usas JSON_LENGTH en comparaciones. Una condición como JSON_LENGTH(col, '$.ruta') > 3 excluirá automáticamente las filas donde la ruta no exista, ya que NULL > 3 evalúa a NULL (y no a verdadero).
Combinación con otras funciones
JSON_LENGTH se combina frecuentemente con funciones de agregación para obtener estadísticas sobre tus datos JSON:
SELECT
AVG(JSON_LENGTH(datos, '$.specs')) AS promedio_specs,
MAX(JSON_LENGTH(datos, '$.imágenes')) AS max_imagenes,
MIN(JSON_LENGTH(datos, '$.etiquetas')) AS min_etiquetas
FROM productos;| promedio_specs | max_imagenes | min_etiquetas |
|---|---|---|
| 4.0000 | 4 | 1 |
También es habitual usar JSON_LENGTH junto con JSON_TYPE para verificar tanto el tipo como el tamaño:
SELECT
nombre,
CASE
WHEN JSON_TYPE(datos->'$.specs') = 'OBJECT' AND JSON_LENGTH(datos, '$.specs') > 0
THEN CONCAT(JSON_LENGTH(datos, '$.specs'), ' especificaciones')
ELSE 'Sin especificaciones'
END AS estado_specs
FROM productos;| nombre | estado_specs |
|---|---|
| iPhone 15 Pro | 5 especificaciones |
| Funda silicona | 2 especificaciones |
| Samsung Galaxy S24 | 3 especificaciones |
| MacBook Air M3 | 6 especificaciones |
JSON_LENGTH te da una visión cuantitativa de tus datos JSON. Pero a veces no solo importa cuántos elementos tiene un documento, sino qué tan profundamente anidado está. En el siguiente artículo veremos JSON_DEPTH para medir la profundidad de anidamiento.
Escrito por Eduardo Lázaro
