JSON_ARRAY_INSERT
La función JSON_ARRAY_INSERT inserta un valor en una posición específica de un array JSON, desplazando los elementos existentes hacia la derecha. Mientras que JSON_ARRAY_APPEND siempre añade al final, JSON_ARRAY_INSERT te da control total sobre dónde colocar el nuevo elemento. Esto es especialmente útil cuando mantienes listas ordenadas (como prioridades, pasos de un proceso, o rankings) donde la posición de cada elemento tiene significado.
Sintaxis
JSON_ARRAY_INSERT(json_doc, ruta, valor [, ruta, valor ...])La función recibe el documento JSON original, seguido de uno o más pares de ruta y valor. La ruta debe incluir un índice de array que indica en qué posición insertar el nuevo valor. Los elementos que estaban en esa posición y en las posiciones siguientes se desplazan una posición hacia la derecha. Si el índice es mayor que la longitud del array, el valor se inserta al final. La función devuelve el documento JSON modificado.
JSON_ARRAY_INSERT(json_doc, '$.ruta[indice]', valor)
JSON_ARRAY_INSERT(json_doc, '$.ruta1[i]', valor1, '$.ruta2[j]', valor2)Comportamiento básico
Veamos cómo funciona la inserción en distintas posiciones. Partimos de un array con tres elementos:
SELECT JSON_ARRAY_INSERT(
'["a", "b", "c"]',
'$[0]', 'NUEVO'
) AS resultado;| resultado |
|---|
| ["NUEVO", "a", "b", "c"] |
Al insertar en la posición 0, el nuevo elemento queda al principio y todos los demás se desplazan una posición. Ahora insertemos en la posición 1 (entre el primer y segundo elemento):
SELECT JSON_ARRAY_INSERT(
'["a", "b", "c"]',
'$[1]', 'NUEVO'
) AS resultado;| resultado |
|---|
| ["a", "NUEVO", "b", "c"] |
Y si insertamos en una posición igual o mayor a la longitud del array, el elemento se coloca al final:
SELECT JSON_ARRAY_INSERT(
'["a", "b", "c"]',
'$[10]', 'NUEVO'
) AS resultado;| resultado |
|---|
| ["a", "b", "c", "NUEVO"] |
No se producen huecos: el índice 10 no crea posiciones vacías, simplemente se inserta al final.
Para insertar en arrays dentro de objetos, especificas la ruta completa con el índice:
SELECT JSON_ARRAY_INSERT(
'{"colores": ["negro", "blanco", "azul"]}',
'$.colores[1]', 'rojo'
) AS resultado;| resultado |
|---|
| {"colores": ["negro", "rojo", "blanco", "azul"]} |
El color "rojo" se insertó en la posición 1, desplazando "blanco" (que estaba en posición 1) a la posición 2, y "azul" (que estaba en posición 2) a la posición 3.
Puedes insertar en múltiples arrays en una sola llamada:
SELECT JSON_ARRAY_INSERT(
'{"prioridades": ["media", "baja"], "pasos": ["inicio", "fin"]}',
'$.prioridades[0]', 'alta',
'$.pasos[1]', 'procesando'
) AS resultado;| resultado |
|---|
| {"pasos": ["inicio", "procesando", "fin"], "prioridades": ["alta", "media", "baja"]} |
Es importante tener en cuenta que cuando proporcionas múltiples pares ruta-valor, las inserciones se aplican secuencialmente de izquierda a derecha. Cada inserción modifica los índices del array, lo que puede afectar a las inserciones posteriores si apuntan al mismo array.
Caso práctico: gestión de listas de prioridades
Imagina un sistema de gestión de tareas donde cada proyecto tiene una lista ordenada de tareas por prioridad:
CREATE TABLE proyectos (
id INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100),
tareas JSON
);
INSERT INTO proyectos (nombre, tareas) VALUES
('Lanzamiento web', '{"pendientes": ["Diseñar landing", "Configurar hosting", "Pruebas finales"], "completadas": []}'),
('App móvil', '{"pendientes": ["Diseño UI", "Backend API", "Testing"], "completadas": ["Investigación de mercado"]}');El cliente pide que se añada "Revisión legal" como segunda prioridad (antes de "Configurar hosting") en el proyecto de lanzamiento web:
UPDATE proyectos
SET tareas = JSON_ARRAY_INSERT(
tareas,
'$.pendientes[1]', 'Revisión legal'
)
WHERE nombre = 'Lanzamiento web';Y también necesita añadir una tarea urgente al principio del proyecto de app móvil:
UPDATE proyectos
SET tareas = JSON_ARRAY_INSERT(
tareas,
'$.pendientes[0]', 'Corrección crítica de seguridad'
)
WHERE nombre = 'App móvil';Después de las actualizaciones:
SELECT
nombre,
tareas->>'$.pendientes' AS pendientes
FROM proyectos;| nombre | pendientes |
|---|---|
| Lanzamiento web | ["Diseñar landing", "Revisión legal", "Configurar hosting", "Pruebas finales"] |
| App móvil | ["Corrección crítica de seguridad", "Diseño UI", "Backend API", "Testing"] |
Las tareas existentes se desplazaron para dar lugar a las nuevas sin perder su orden relativo.
Caso práctico: insertar pasos en un proceso
Considera un flujo de trabajo donde los pasos de un proceso se almacenan como un array JSON y necesitas insertar pasos intermedios:
CREATE TABLE flujos_trabajo (
id INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100),
config JSON
);
INSERT INTO flujos_trabajo (nombre, config) VALUES
('Procesamiento de pedido',
'{"pasos": ["Recibir pedido", "Verificar stock", "Preparar envío", "Entregar"], "activo": true}');Se decide que después de "Verificar stock" se necesitan dos pasos adicionales: "Procesar pago" y "Generar factura":
UPDATE flujos_trabajo
SET config = JSON_ARRAY_INSERT(
config,
'$.pasos[2]', 'Procesar pago'
)
WHERE nombre = 'Procesamiento de pedido';
UPDATE flujos_trabajo
SET config = JSON_ARRAY_INSERT(
config,
'$.pasos[3]', 'Generar factura'
)
WHERE nombre = 'Procesamiento de pedido';SELECT JSON_PRETTY(config->'$.pasos') AS pasos
FROM flujos_trabajo
WHERE nombre = 'Procesamiento de pedido';| pasos |
|---|
| ["Recibir pedido", "Verificar stock", "Procesar pago", "Generar factura", "Preparar envío", "Entregar"] |
Los nuevos pasos se insertaron en las posiciones correctas sin alterar la secuencia de los pasos existentes. Observa que la segunda inserción usa el índice 3 (no 2) porque la primera inserción ya desplazó los elementos.
Caso práctico: mantener un ranking ordenado
Si mantienes un ranking de productos más vendidos como un array JSON, puedes insertar nuevos productos en la posición correspondiente:
CREATE TABLE rankings (
id INT PRIMARY KEY AUTO_INCREMENT,
categoria VARCHAR(50),
top_productos JSON
);
INSERT INTO rankings (categoria, top_productos) VALUES
('Smartphones', '["iPhone 15 Pro", "Samsung Galaxy S24", "Google Pixel 8", "Xiaomi 14"]'),
('Portátiles', '["MacBook Air M3", "ThinkPad X1", "Dell XPS 15"]');Un nuevo modelo de OnePlus irrumpe en la segunda posición del ranking de smartphones:
UPDATE rankings
SET top_productos = JSON_ARRAY_INSERT(
top_productos,
'$[1]', 'OnePlus 12'
)
WHERE categoria = 'Smartphones';SELECT categoria, top_productos
FROM rankings
WHERE categoria = 'Smartphones';| categoria | top_productos |
|---|---|
| Smartphones | ["iPhone 15 Pro", "OnePlus 12", "Samsung Galaxy S24", "Google Pixel 8", "Xiaomi 14"] |
El OnePlus 12 ahora está en segunda posición, y todos los demás se desplazaron una posición hacia abajo.
Manejo de NULL
Cuando el documento JSON es NULL, la función devuelve NULL:
SELECT JSON_ARRAY_INSERT(NULL, '$[0]', 'valor') AS resultado;| resultado |
|---|
| NULL |
Si la ruta no apunta a un array existente, el documento se devuelve sin cambios:
SELECT JSON_ARRAY_INSERT(
'{"nombre": "iPhone"}',
'$.tags[0]', 'premium'
) AS resultado;| resultado |
|---|
| {"nombre": "iPhone"} |
La ruta $.tags no existe, por lo que no hay ningún array donde insertar. El documento se devuelve tal cual. Si necesitas crear el array cuando no existe, primero usa JSON_SET para crear un array vacío o con el elemento inicial.
Combinación con otras funciones
Puedes combinar JSON_ARRAY_INSERT con JSON_LENGTH para insertar en la última posición de forma dinámica (aunque para eso es más sencillo usar JSON_ARRAY_APPEND):
SELECT JSON_ARRAY_INSERT(
'["a", "b", "c"]',
CONCAT('$[', JSON_LENGTH('["a", "b", "c"]'), ']'),
'al final'
) AS resultado;| resultado |
|---|
| ["a", "b", "c", "al final"] |
Una combinación más práctica es verificar con JSON_CONTAINS si el elemento ya existe antes de insertarlo:
UPDATE rankings
SET top_productos = JSON_ARRAY_INSERT(top_productos, '$[0]', 'Nuevo modelo')
WHERE categoria = 'Smartphones'
AND NOT JSON_CONTAINS(top_productos, '"Nuevo modelo"');Y para insertar un elemento justo antes de otro elemento conocido, puedes usar JSON_SEARCH para encontrar su posición:
SELECT JSON_SEARCH('["a", "b", "c", "d"]', 'one', 'c') AS posicion_c;| posicion_c |
|---|
| "$[2]" |
Con esa información, sabes que para insertar antes de "c" debes usar el índice 2. Este tipo de combinación te da un control preciso sobre la posición de inserción basándote en el contenido del array. En el siguiente artículo veremos JSON_ARRAYAGG para crear arrays JSON desde consultas de agregación.
Escrito por Eduardo Lázaro
