JSON_OVERLAPS
La función JSON_OVERLAPS compara dos documentos JSON y devuelve verdadero si comparten al menos un elemento en común. Es especialmente útil para detectar intersecciones entre arrays, por ejemplo, cuando quieres encontrar productos que compartan etiquetas, usuarios con intereses similares o registros con categorías coincidentes.
Sintaxis
JSON_OVERLAPS(documento_json1, documento_json2)La función recibe dos expresiones JSON y devuelve 1 si los documentos tienen al menos un elemento compartido, o 0 si no tienen ninguno. El comportamiento varía según el tipo de los documentos comparados:
Cuando ambos argumentos son arrays, la función comprueba si existe al menos un valor presente en ambos arrays. Cuando ambos son objetos, comprueba si comparten al menos una clave con el mismo valor. Cuando uno es un escalar y el otro un array, comprueba si el escalar es miembro del array. Si ambos son escalares, simplemente compara si son iguales.
JSON_OVERLAPS requiere MySQL 8.0.17 o superior y, al igual que MEMBER OF, puede aprovechar los índices multi-valor para búsquedas eficientes.
Comportamiento básico
Empecemos con arrays simples:
SELECT JSON_OVERLAPS('[1, 2, 3]', '[3, 4, 5]') AS resultado;| resultado |
|---|
| 1 |
Ambos arrays contienen el valor 3, por lo que hay solapamiento. Si no hay elementos comunes:
SELECT JSON_OVERLAPS('[1, 2, 3]', '[4, 5, 6]') AS resultado;| resultado |
|---|
| 0 |
La comparación de tipos es estricta, igual que con MEMBER OF:
SELECT JSON_OVERLAPS('[1, 2, 3]', '["1", "2", "3"]') AS resultado;| resultado |
|---|
| 0 |
Los enteros 1, 2, 3 no son iguales a las cadenas "1", "2", "3", por lo que no hay solapamiento.
Con objetos, la función busca pares clave-valor comunes:
SELECT JSON_OVERLAPS(
'{"color": "rojo", "talla": "M"}',
'{"color": "rojo", "peso": 0.5}'
) AS resultado;| resultado |
|---|
| 1 |
Ambos objetos comparten la clave "color" con el valor "rojo". Si la clave coincide pero el valor es diferente, no se considera solapamiento:
SELECT JSON_OVERLAPS(
'{"color": "rojo", "talla": "M"}',
'{"color": "azul", "peso": 0.5}'
) AS resultado;| resultado |
|---|
| 0 |
Aunque ambos tienen la clave "color", los valores son diferentes, así que no hay solapamiento.
Caso práctico: sistema de etiquetas de productos
En una tienda online con productos etiquetados, JSON_OVERLAPS permite encontrar productos que compartan etiquetas con un producto dado:
CREATE TABLE productos (
id INT AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(200),
precio DECIMAL(10,2),
etiquetas JSON
);
INSERT INTO productos (nombre, precio, etiquetas) VALUES
('iPhone 15 Pro', 1299.99, '["smartphone", "apple", "5g", "premium"]'),
('Samsung Galaxy S24', 899.99, '["smartphone", "samsung", "5g", "android"]'),
('Google Pixel 8', 699.00, '["smartphone", "google", "5g", "android"]'),
('MacBook Air M3', 1399.00, '["portatil", "apple", "ultrabook"]'),
('iPad Air', 699.00, '["tablet", "apple", "educacion"]'),
('Sony WH-1000XM5', 349.00, '["auriculares", "sony", "bluetooth", "premium"]');Para encontrar productos que compartan etiquetas con el iPhone 15 Pro (etiquetas: smartphone, apple, 5g, premium):
SELECT
p2.nombre,
p2.precio,
p2.etiquetas
FROM productos p1
JOIN productos p2 ON p1.id != p2.id
WHERE p1.id = 1
AND JSON_OVERLAPS(p1.etiquetas, p2.etiquetas);| nombre | precio | etiquetas |
|---|---|---|
| Samsung Galaxy S24 | 899.99 | ["smartphone", "samsung", "5g", "android"] |
| Google Pixel 8 | 699.00 | ["smartphone", "google", "5g", "android"] |
| MacBook Air M3 | 1399.00 | ["portatil", "apple", "ultrabook"] |
| iPad Air | 699.00 | ["tablet", "apple", "educacion"] |
| Sony WH-1000XM5 | 349.00 | ["auriculares", "sony", "bluetooth", "premium"] |
Todos estos productos comparten al menos una etiqueta con el iPhone. El Samsung y el Pixel comparten "smartphone" y "5g", el MacBook y el iPad comparten "apple", y los Sony comparten "premium". Este es el patrón básico de un sistema de recomendaciones: "productos relacionados".
Caso práctico: filtrar por múltiples criterios
Supongamos que un usuario busca productos que coincidan con cualquiera de sus intereses. En lugar de escribir múltiples condiciones OR, puedes usar JSON_OVERLAPS:
SET @intereses_usuario = '["premium", "bluetooth"]';
SELECT nombre, precio, etiquetas
FROM productos
WHERE JSON_OVERLAPS(etiquetas, @intereses_usuario);| nombre | precio | etiquetas |
|---|---|---|
| iPhone 15 Pro | 1299.99 | ["smartphone", "apple", "5g", "premium"] |
| Sony WH-1000XM5 | 349.00 | ["auriculares", "sony", "bluetooth", "premium"] |
La consulta devuelve productos que tengan la etiqueta "premium" o "bluetooth" (o ambas). Es una forma elegante de implementar filtros flexibles donde el usuario puede seleccionar múltiples opciones.
Para verificar que un producto tenga todas las etiquetas (en lugar de al menos una), usarías JSON_CONTAINS en su lugar.
Caso práctico: detectar conflictos de horario
Imagina un sistema de reservas donde cada reserva tiene un array de horas ocupadas:
CREATE TABLE reservas_sala (
id INT AUTO_INCREMENT PRIMARY KEY,
sala VARCHAR(50),
fecha DATE,
empleado VARCHAR(100),
horas JSON
);
INSERT INTO reservas_sala (sala, fecha, empleado, horas) VALUES
('Sala A', '2025-06-15', 'María García', '[9, 10, 11]'),
('Sala A', '2025-06-15', 'Carlos López', '[14, 15, 16]'),
('Sala B', '2025-06-15', 'Ana Martínez', '[10, 11, 12]');Para verificar si una nueva reserva de la Sala A entre las 11 y las 13 tiene conflicto con reservas existentes:
SET @nueva_reserva = '[11, 12, 13]';
SELECT
empleado,
horas,
JSON_OVERLAPS(horas, @nueva_reserva) AS tiene_conflicto
FROM reservas_sala
WHERE sala = 'Sala A'
AND fecha = '2025-06-15';| empleado | horas | tiene_conflicto |
|---|---|---|
| María García | [9, 10, 11] | 1 |
| Carlos López | [14, 15, 16] | 0 |
La reserva de María tiene conflicto porque la hora 11 está en ambos arrays. La de Carlos no tiene conflicto. Para bloquear la reserva solo si hay conflicto:
SELECT COUNT(*) AS conflictos
FROM reservas_sala
WHERE sala = 'Sala A'
AND fecha = '2025-06-15'
AND JSON_OVERLAPS(horas, @nueva_reserva);| conflictos |
|---|
| 1 |
Si el resultado es mayor que cero, la aplicación puede rechazar la nueva reserva.
Manejo de NULL
Si cualquiera de los argumentos es NULL, JSON_OVERLAPS devuelve NULL:
SELECT JSON_OVERLAPS(NULL, '[1, 2, 3]') AS resultado;| resultado |
|---|
| NULL |
SELECT JSON_OVERLAPS('[1, 2, 3]', NULL) AS resultado;| resultado |
|---|
| NULL |
Con arrays vacíos, el resultado es 0 porque no hay elementos que puedan coincidir:
SELECT JSON_OVERLAPS('[]', '[1, 2, 3]') AS resultado;| resultado |
|---|
| 0 |
Si ambos arrays contienen null como elemento, sí se detecta solapamiento:
SELECT JSON_OVERLAPS('[1, null, 3]', '[null, 4, 5]') AS resultado;| resultado |
|---|
| 1 |
Combinación con otras funciones
Puedes combinar JSON_OVERLAPS con otras funciones para obtener información más detallada. Por ejemplo, para saber cuántas etiquetas comparten dos productos, no basta con JSON_OVERLAPS (que solo dice sí o no). Puedes complementarlo con subconsultas:
SELECT
p1.nombre AS producto_1,
p2.nombre AS producto_2,
JSON_OVERLAPS(p1.etiquetas, p2.etiquetas) AS se_solapan
FROM productos p1
CROSS JOIN productos p2
WHERE p1.id < p2.id
AND JSON_OVERLAPS(p1.etiquetas, p2.etiquetas) = 1
ORDER BY p1.nombre, p2.nombre;| producto_1 | producto_2 | se_solapan |
|---|---|---|
| Google Pixel 8 | Samsung Galaxy S24 | 1 |
| iPad Air | MacBook Air M3 | 1 |
| iPhone 15 Pro | Google Pixel 8 | 1 |
| iPhone 15 Pro | iPad Air | 1 |
| iPhone 15 Pro | MacBook Air M3 | 1 |
| iPhone 15 Pro | Samsung Galaxy S24 | 1 |
| iPhone 15 Pro | Sony WH-1000XM5 | 1 |
Esta consulta muestra todos los pares de productos que comparten al menos una etiqueta, lo que puede alimentar un algoritmo de recomendaciones.
Al igual que MEMBER OF, JSON_OVERLAPS puede aprovechar los índices multi-valor cuando uno de los operandos es una columna JSON indexada, lo que mejora significativamente el rendimiento en tablas grandes.
En el siguiente artículo veremos JSON_PRETTY para formatear documentos JSON de forma legible.
Escrito por Eduardo Lázaro
