Si JSONB es como un cofre mágico donde metemos datos, entonces || y jsonb_concat() son las herramientas que nos permiten juntar esos cofres o cambiar lo que hay dentro. En la vida real, puede que necesites unir varios objetos JSON, añadir datos de uno a otro o juntar arrays en una sola lista.
Por ejemplo, imagina que tienes dos objetos JSONB:
{"nombre": "Alice", "edad": 25}
y
{"ciudad": "Wonderland", "aficiones": ["leer", "ajedrez"]}
Quieres obtener:
{"nombre": "Alice", "edad": 25, "ciudad": "Wonderland", "aficiones": ["leer", "ajedrez"]}
O unir dos arrays JSONB:
[1, 2, 3]
y
[4, 5, 6]
para que el resultado sea así:
[1, 2, 3, 4, 5, 6]
Todo esto se hace con || o jsonb_concat(). Vamos a ver cómo funciona.
El operador || para unir JSONB
El operador || te deja unir dos objetos o arrays JSONB en PostgreSQL. Es fácil, rápido y directo de usar. Aquí tienes las reglas básicas:
- Si unes dos objetos JSONB, el resultado tendrá las claves y valores de ambos objetos.
- Si hay claves repetidas, el valor del operando derecho reemplaza al del izquierdo.
- Si unes arrays JSONB, los elementos del array izquierdo y derecho se juntan en un solo array.
Ejemplo 1: Unión de dos objetos JSONB
SELECT '{"nombre": "Alice", "edad": 25}'::jsonb || '{"ciudad": "Wonderland", "aficiones": ["leer", "ajedrez"]}'::jsonb AS objeto_unido;
Resultado:
{"nombre": "Alice", "edad": 25, "ciudad": "Wonderland", "aficiones": ["leer", "ajedrez"]}
Ejemplo 2: Actualización de valores cuando las claves coinciden
SELECT '{"nombre": "Alice", "edad": 25}'::jsonb || '{"edad": 30, "ciudad": "Wonderland"}'::jsonb AS objeto_actualizado;
Resultado:
{"nombre": "Alice", "edad": 30, "ciudad": "Wonderland"}
Fíjate que el valor de la clave "edad" del objeto derecho reemplazó al del izquierdo.
Ejemplo 3: Unión de arrays
SELECT '[1, 2, 3]'::jsonb || '[4, 5, 6]'::jsonb AS array_unido;
Resultado:
[1, 2, 3, 4, 5, 6]
La función jsonb_concat() para unir JSONB
La función jsonb_concat() funciona igual que el operador ||, pero te da más flexibilidad si necesitas usarla en funciones, triggers o consultas dinámicas. Recibe dos argumentos tipo JSONB y devuelve el resultado unido.
Ejemplo: usando jsonb_concat()
SELECT jsonb_concat('{"a": 1, "b": 2}'::jsonb, '{"b": 3, "c": 4}'::jsonb) AS combinado;
Resultado:
{"a": 1, "b": 3, "c": 4}
Unión de objetos y arrays: detalles y matices
Cuando unes objetos con claves repetidas, tienes que saber que los valores del objeto derecho tienen prioridad.
Por ejemplo:
SELECT '{"clave1": "valor1"}'::jsonb || '{"clave1": "valor2"}'::jsonb AS resultado;
Resultado:
{"clave1": "valor2"}
Si quieres evitar que se reemplacen valores, deberías guardar esos datos en claves distintas o usar otro enfoque (por ejemplo, un array).
Y los arrays siempre se unen añadiendo los elementos del array derecho al izquierdo. Por ejemplo:
SELECT '["a", "b"]'::jsonb || '["c", "d"]'::jsonb AS resultado;
Resultado:
["a", "b", "c", "d"]
Si dentro del array hay objetos, el orden de los objetos se mantiene:
SELECT '[{"id": 1}, {"id": 2}]'::jsonb || '[{"id": 3}]'::jsonb AS resultado;
Resultado:
[{"id": 1}, {"id": 2}, {"id": 3}]
Ejemplos prácticos
Actualización del perfil de usuario. Supón que tenemos una tabla usuarios donde los perfiles se guardan en formato JSONB:
CREATE TABLE usuarios (
id SERIAL PRIMARY KEY,
perfil JSONB
);
INSERT INTO usuarios (perfil) VALUES ('{"nombre": "Alice", "edad": 25}');
Ahora queremos añadir la ciudad de residencia:
UPDATE usuarios
SET perfil = perfil || '{"ciudad": "Wonderland"}'
WHERE id = 1;
Resultado de la consulta:
{"nombre": "Alice", "edad": 25, "ciudad": "Wonderland"}
Unión de datos de pedidos. Supón que tenemos una tabla pedidos:
CREATE TABLE pedidos (
id SERIAL PRIMARY KEY,
detalles JSONB
);
INSERT INTO pedidos (detalles) VALUES ('{"articulos": [{"producto": "portatil", "cantidad": 1}]}');
Ahora añadimos otro producto al pedido:
UPDATE pedidos
SET detalles = jsonb_set(
detalles,
'{articulos}',
detalles->'articulos' || '[{"producto": "raton", "cantidad": 2}]'::jsonb
)
WHERE id = 1;
Resultado de la consulta:
{"articulos": [{"producto": "portatil", "cantidad": 1}, {"producto": "raton", "cantidad": 2}]}
Diferencias entre || y jsonb_concat()
En la práctica, el operador || y la función jsonb_concat() hacen lo mismo. Usa || si escribes consultas simples, porque es más corto. La función jsonb_concat() es útil cuando necesitas llamarla explícitamente dentro de un programa o trigger.
Errores típicos y cómo evitarlos
Error: intentar unir tipos incompatibles.
SELECT '{"clave": "valor"}'::jsonb || '["valor"]'::jsonb;
Resultado:
ERROR: no se pueden concatenar objetos y arrays jsonb
Aquí a la izquierda hay un objeto y a la derecha un array — PostgreSQL no puede unirlos así sin más. Para que funcione, ambos operandos tienen que ser del mismo tipo: o dos objetos, o dos arrays.
Olvido: no tener índices al trabajar con JSONB
Si filtras mucho por valores dentro de campos JSONB y no tienes índices, las consultas pueden ir lentísimas. No es un error clásico, pero el bajón de rendimiento se nota. No te olvides de usar índices GIN:
CREATE INDEX idx_datos_perfil ON empleados USING gin(perfil);
GO TO FULL VERSION