JSON_DEPTH

La función JSON_DEPTH mide cuántos niveles de anidamiento tiene un documento JSON. En estructuras de datos complejas, donde los objetos contienen otros objetos que a su vez contienen arrays, es fácil perder la noción de cuán profunda es la jerarquía. JSON_DEPTH te da esa respuesta como un simple número entero, lo que resulta muy útil para detectar documentos excesivamente complejos, validar que los datos cumplen con un esquema esperado, o analizar la estructura de datos importados desde fuentes externas.

Sintaxis

JSON_DEPTH(json_doc)

La función recibe un único argumento: el documento JSON cuya profundidad quieres medir. Devuelve un entero que representa el nivel máximo de anidamiento. Si el argumento es NULL, devuelve NULL.

Las reglas de conteo de profundidad son las siguientes: un valor escalar (cadena, número, booleano o null) tiene profundidad 1. Un array o un objeto vacíos también tienen profundidad 1. Un array o un objeto con elementos no vacíos tienen una profundidad igual a 1 más la profundidad máxima de sus elementos internos.

Comportamiento básico

Los valores escalares tienen la profundidad mínima:

SELECT
    JSON_DEPTH('"texto"') AS cadena,
    JSON_DEPTH('42') AS numero,
    JSON_DEPTH('true') AS booleano,
    JSON_DEPTH('null') AS nulo;
cadenanumerobooleanonulo
1111

Los contenedores vacíos también tienen profundidad 1, porque el propio contenedor cuenta como un nivel aunque no contenga nada:

SELECT
    JSON_DEPTH('[]') AS array_vacio,
    JSON_DEPTH('{}') AS objeto_vacio;
array_vacioobjeto_vacio
11

Un array o un objeto con elementos escalares tienen profundidad 2: un nivel para el contenedor y otro para los elementos:

SELECT
    JSON_DEPTH('[1, 2, 3]') AS array_simple,
    JSON_DEPTH('{"a": 1, "b": 2}') AS objeto_simple;
array_simpleobjeto_simple
22

A medida que se anidan estructuras, la profundidad aumenta:

SELECT
    JSON_DEPTH('{"a": [1, 2]}') AS nivel_3,
    JSON_DEPTH('{"a": {"b": [1, 2]}}') AS nivel_4,
    JSON_DEPTH('{"a": {"b": {"c": [1]}}}') AS nivel_5;
nivel_3nivel_4nivel_5
345

En el primer caso tenemos: objeto (nivel 1) que contiene un array (nivel 2) que contiene escalares (nivel 3). La profundidad siempre refleja la rama más profunda del documento.

Caso práctico: análisis de complejidad de productos

Imagina una tienda donde los productos tienen atributos JSON con distinto grado de complejidad. Algunos productos solo tienen datos planos, mientras que otros tienen especificaciones anidadas en varios niveles:

CREATE TABLE productos (
    id INT PRIMARY KEY AUTO_INCREMENT,
    nombre VARCHAR(100),
    atributos JSON
);
 
INSERT INTO productos (nombre, atributos) VALUES
('Cable USB-C',
 '{"precio": 12.50, "longitud": "1m", "color": "negro"}'),
('iPhone 15 Pro',
 '{"precio": 1299, "specs": {"pantalla": {"tamaño": 6.1, "tipo": "OLED", "resolución": "2556x1179"}, "cámara": {"principal": "48MP", "ultra_angular": "12MP"}}, "colores": ["titanio", "negro", "blanco"]}'),
('Funda silicona',
 '{"precio": 29.99, "compatible": ["iPhone 15", "iPhone 15 Pro"]}'),
('MacBook Air M3',
 '{"precio": 1399, "specs": {"procesador": {"nombre": "M3", "núcleos": {"rendimiento": 4, "eficiencia": 4}}, "pantalla": {"tamaño": 13.6, "tipo": "Liquid Retina"}, "puertos": ["MagSafe", "USB-C", "USB-C", "mini-jack"]}}');

Para medir la complejidad de cada producto:

SELECT
    nombre,
    JSON_DEPTH(atributos) AS profundidad,
    CASE
        WHEN JSON_DEPTH(atributos) <= 2 THEN 'Simple'
        WHEN JSON_DEPTH(atributos) <= 4 THEN 'Moderado'
        ELSE 'Complejo'
    END AS complejidad
FROM productos
ORDER BY profundidad DESC;
nombreprofundidadcomplejidad
MacBook Air M35Complejo
iPhone 15 Pro4Moderado
Funda silicona2Simple
Cable USB-C2Simple

El MacBook Air tiene la estructura más profunda porque sus especificaciones del procesador contienen un objeto anidado con núcleos, lo que genera cinco niveles: objeto raíz, specs, procesador, núcleos y los valores escalares dentro.

Caso práctico: validación de esquema por profundidad

Cuando recibes datos de APIs externas o importaciones, puedes establecer un límite máximo de profundidad para evitar documentos excesivamente complejos que dificulten las consultas:

CREATE TABLE importaciones (
    id INT PRIMARY KEY AUTO_INCREMENT,
    origen VARCHAR(100),
    datos JSON,
    fecha DATETIME DEFAULT CURRENT_TIMESTAMP
);
 
INSERT INTO importaciones (origen, datos) VALUES
('API Proveedor A', '{"producto": "Teclado", "precio": 45.00}'),
('API Proveedor B', '{"producto": "Monitor", "specs": {"pantalla": {"resolución": "4K", "panel": {"tipo": "IPS", "brillo": {"típico": 350, "máximo": 400}}}}}'),
('CSV Inventario', '{"productos": [{"id": 1, "nombre": "Ratón"}, {"id": 2, "nombre": "Alfombrilla"}]}'),
('API Proveedor C', '{"producto": "Webcam", "precio": 79.99, "specs": {"resolución": "1080p"}}');

Para identificar importaciones con datos demasiado profundos que podrían necesitar normalización:

SELECT
    origen,
    JSON_DEPTH(datos) AS profundidad,
    CASE
        WHEN JSON_DEPTH(datos) > 4 THEN 'Revisar: demasiado anidado'
        ELSE 'OK'
    END AS estado
FROM importaciones;
origenprofundidadestado
API Proveedor A2OK
API Proveedor B6Revisar: demasiado anidado
CSV Inventario3OK
API Proveedor C3OK

La importación del Proveedor B tiene 6 niveles de profundidad, lo que sugiere que los datos podrían beneficiarse de una reestructuración antes de ser consultados frecuentemente.

Caso práctico: comparación de complejidad entre categorías

Si tienes productos agrupados por categoría, puedes usar JSON_DEPTH con funciones de agregación para comparar la complejidad promedio de los datos JSON por categoría:

CREATE TABLE productos_cat (
    id INT PRIMARY KEY AUTO_INCREMENT,
    nombre VARCHAR(100),
    categoria VARCHAR(50),
    detalles JSON
);
 
INSERT INTO productos_cat (nombre, categoria, detalles) VALUES
('iPhone 15 Pro', 'Electrónica', '{"specs": {"pantalla": {"tamaño": 6.1}, "cámara": {"principal": "48MP"}}, "precio": 1299}'),
('Samsung Galaxy S24', 'Electrónica', '{"specs": {"pantalla": {"tamaño": 6.2}, "batería": 4000}, "precio": 899}'),
('Camiseta algodón', 'Ropa', '{"tallas": ["S", "M", "L", "XL"], "color": "blanco", "precio": 24.99}'),
('Pantalón vaquero', 'Ropa', '{"tallas": ["38", "40", "42"], "color": "azul", "precio": 59.99}'),
('Silla ergonómica', 'Hogar', '{"materiales": {"estructura": "acero", "asiento": "malla"}, "ajustes": {"altura": true, "reposabrazos": true}, "precio": 349}');
SELECT
    categoria,
    COUNT(*) AS total_productos,
    AVG(JSON_DEPTH(detalles)) AS profundidad_promedio,
    MAX(JSON_DEPTH(detalles)) AS profundidad_maxima
FROM productos_cat
GROUP BY categoria
ORDER BY profundidad_promedio DESC;
categoriatotal_productosprofundidad_promedioprofundidad_maxima
Electrónica24.00004
Hogar13.00003
Ropa22.00002

Los productos de electrónica tienden a tener datos JSON más profundos porque sus especificaciones técnicas son naturalmente jerárquicas, mientras que la ropa tiene una estructura más plana.

Manejo de NULL

Cuando el argumento es NULL, JSON_DEPTH devuelve NULL:

SELECT JSON_DEPTH(NULL) AS resultado;
resultado
NULL

Un array que contiene un valor null JSON tiene profundidad 2, no 1, porque el null es un elemento dentro del array:

SELECT JSON_DEPTH('[null]') AS con_null_json;
con_null_json
2

Es decir, el null JSON es un valor escalar con profundidad 1, y el array que lo contiene suma un nivel más.

Combinación con otras funciones

JSON_DEPTH se combina bien con JSON_LENGTH para obtener un perfil completo de la estructura de un documento:

SELECT
    nombre,
    JSON_DEPTH(atributos) AS profundidad,
    JSON_LENGTH(atributos) AS claves_raiz,
    JSON_TYPE(atributos) AS tipo_raiz
FROM productos;
nombreprofundidadclaves_raiztipo_raiz
Cable USB-C23OBJECT
iPhone 15 Pro43OBJECT
Funda silicona22OBJECT
MacBook Air M352OBJECT

Este perfil te dice que el MacBook Air, a pesar de tener solo 2 claves en la raíz, tiene una estructura mucho más profunda que el cable USB-C, que tiene 3 claves pero todas planas. La relación entre longitud y profundidad te da una idea de si la complejidad está en la amplitud (muchas claves) o en el anidamiento (muchos niveles). En el siguiente artículo veremos JSON_VALID para validar documentos JSON.

Escrito por Eduardo Lázaro