🧚 ¡Oye! Beekeeper Studio es una GUI de bases de datos rápida, moderna y de código abierto Descarga
23 de marzo de 2025 Por Matthew Rathbone

PostgreSQL ofrece un soporte muy potente para almacenar y consultar datos JSON con sus tipos de datos json y jsonb. El tipo jsonb es especialmente útil porque guarda los datos en formato binario, lo que permite indexar y consultar de forma más eficiente que con el tipo json, basado en texto.

En este tutorial vamos a ver las operaciones JSON más comunes en PostgreSQL con ejemplos prácticos que puedes usar en tus aplicaciones.

Crear datos JSON

Empecemos creando una tabla con una columna jsonb e insertando algunos datos de ejemplo:

CREATE TABLE customers (
    id SERIAL PRIMARY KEY,
    info JSONB
);

-- Insert a customer with basic information
INSERT INTO customers (info) VALUES (
    '{"name": "Alice Smith", "email": "alice@example.com", "age": 32, "addresses": [
        {"type": "home", "city": "San Francisco", "state": "CA"}, 
        {"type": "work", "city": "Oakland", "state": "CA"}
     ]}'
);

-- Insert another customer
INSERT INTO customers (info) VALUES (
    '{"name": "Bob Johnson", "email": "bob@example.com", "age": 45, "addresses": [
        {"type": "home", "city": "Seattle", "state": "WA"}
     ], "orders": [101, 102, 103]}'
);

Operaciones JSON básicas

Obtener el documento JSON completo

SELECT info FROM customers WHERE id = 1;

Resultado:

{
  "age": 32,
  "name": "Alice Smith",
  "email": "alice@example.com",
  "addresses": [
    {"city": "San Francisco", "type": "home", "state": "CA"},
    {"city": "Oakland", "type": "work", "state": "CA"}
  ]
}

Extraer valores de JSON

PostgreSQL ofrece varios operadores para extraer valores de JSON:

Extraer un campo específico con el operador -> (devuelve JSON)

-- Get the name field as JSON
SELECT info -> 'name' FROM customers;

Resultado:

"Alice Smith"
"Bob Johnson"

Extraer un campo específico con el operador -» (devuelve texto)

-- Get the name field as text
SELECT info ->> 'name' AS customer_name FROM customers;

Resultado:

customer_name
----------------
Alice Smith
Bob Johnson

Acceder a objetos anidados

-- Getting the first address (array element 0) city
SELECT info -> 'addresses' -> 0 ->> 'city' AS home_city FROM customers;

Resultado:

home_city
------------
San Francisco
Seattle

Usar el operador #> para acceder por ruta

-- Using the path syntax to get the same value
SELECT info #> '{addresses,0,city}' FROM customers;

Resultado:

"San Francisco"
"Seattle"

Usar el operador #» para acceder por ruta como texto

-- Using the path syntax to get the same value as text
SELECT info #>> '{addresses,0,city}' AS home_city FROM customers;

Resultado:

home_city
------------
San Francisco
Seattle

Modificar datos JSON

PostgreSQL ofrece varias funciones para modificar datos JSON:

Agregar un campo con jsonb_set

-- Add a new field 'premium_customer' to a customer
UPDATE customers
SET info = jsonb_set(info, '{premium_customer}', 'true')
WHERE id = 1;

Eliminar un campo con el operador -

-- Remove the premium_customer field
UPDATE customers
SET info = info - 'premium_customer'
WHERE id = 1;

Combinar objetos JSON con ||

-- Add multiple fields by merging objects
UPDATE customers
SET info = info || '{"status": "active", "last_login": "2025-03-23"}'::jsonb
WHERE id = 1;

Actualizar un campo anidado

-- Update a nested field (home address state)
UPDATE customers
SET info = jsonb_set(
    info, 
    '{addresses,0,state}', 
    '"NY"'::jsonb
)
WHERE id = 1;

Consultar arrays JSON

Trabajar con arrays JSON es una operación común:

Obtener la longitud de un array

-- Get the number of addresses for each customer
SELECT 
    info ->> 'name' AS customer_name,
    jsonb_array_length(info -> 'addresses') AS address_count
FROM customers;

Resultado:

customer_name  | address_count
---------------+--------------
Alice Smith    | 2
Bob Johnson    | 1

Extraer elementos específicos de un array

-- Get the second address (index 1) for Alice
SELECT info -> 'addresses' -> 1 FROM customers WHERE id = 1;

Resultado:

{"city": "Oakland", "type": "work", "state": "CA"}

Desanidar arrays para consultar elementos individuales

-- Unnest the addresses array to query individual addresses
SELECT 
    c.id,
    c.info ->> 'name' AS customer_name,
    jsonb_array_elements(c.info -> 'addresses') AS address
FROM customers c;

Resultado:

id | customer_name | address
---+---------------+------------------------------------------------------
1  | Alice Smith   | {"city": "San Francisco", "type": "home", "state": "NY"}
1  | Alice Smith   | {"city": "Oakland", "type": "work", "state": "CA"}
2  | Bob Johnson   | {"city": "Seattle", "type": "home", "state": "WA"}

Filtrar con arrays desanidados

-- Find customers with addresses in CA
SELECT DISTINCT
    c.id,
    c.info ->> 'name' AS customer_name
FROM customers c,
     jsonb_array_elements(c.info -> 'addresses') AS addr
WHERE addr ->> 'state' = 'CA';

Resultado:

id | customer_name
---+--------------
1  | Alice Smith

Verificar claves y valores

Verificar si existe una clave

-- Find customers who have the 'orders' key
SELECT id, info ->> 'name' AS customer_name
FROM customers
WHERE info ? 'orders';

Resultado:

id | customer_name
---+--------------
2  | Bob Johnson

Buscar valores en arrays

-- Find customers with a specific order number
SELECT id, info ->> 'name' AS customer_name
FROM customers
WHERE info -> 'orders' ? '101';

Resultado:

id | customer_name
---+--------------
2  | Bob Johnson

Verificar si algún elemento del array coincide

-- Find customers who have an address in Oakland (using path operators)
SELECT id, info ->> 'name' AS customer_name
FROM customers
WHERE info @> '{"addresses": [{"city": "Oakland"}]}';

Resultado:

id | customer_name
---+--------------
1  | Alice Smith

Indexar datos JSON

En bases de datos de producción con grandes volúmenes de JSON, indexar bien es fundamental:

Crear un índice GIN para consultas de contención

-- Create a GIN index for faster containment operations
CREATE INDEX idx_customers_info ON customers USING GIN (info);

Crear un índice específico para un campo JSON

-- Create an index on the 'email' field for fast lookups
CREATE INDEX idx_customers_email ON customers ((info ->> 'email'));

Usar campos indexados en consultas

-- This query can use the index we created above
SELECT id, info ->> 'name' AS customer_name
FROM customers
WHERE info ->> 'email' = 'alice@example.com';

Convertir entre JSON y tablas

Convertir JSON en filas (jsonb_to_record)

-- Extract JSON fields into a tabular structure
SELECT 
    id,
    rec.name,
    rec.email,
    rec.age
FROM 
    customers,
    jsonb_to_record(info) AS rec(
        name text,
        email text,
        age int
    );

Resultado:

id | name         | email             | age
---+--------------+-------------------+-----
1  | Alice Smith  | alice@example.com | 32
2  | Bob Johnson  | bob@example.com   | 45

Convertir arrays anidados en tablas (jsonb_to_recordset)

-- Extract addresses from all customers into a table
SELECT 
    c.id,
    c.info ->> 'name' AS customer_name,
    addr.type AS address_type,
    addr.city,
    addr.state
FROM 
    customers c,
    jsonb_to_recordset(c.info -> 'addresses') AS addr(
        type text,
        city text,
        state text
    );

Resultado:

id | customer_name | address_type | city          | state
---+---------------+--------------+---------------+------
1  | Alice Smith   | home         | San Francisco | NY
1  | Alice Smith   | work         | Oakland       | CA
2  | Bob Johnson   | home         | Seattle       | WA

Convertir resultados de consultas a JSON

-- Aggregate customer orders into a JSON array
SELECT
    c.id,
    c.info ->> 'name' AS customer_name,
    json_agg(o.order_id) AS orders
FROM 
    customers c
    CROSS JOIN LATERAL (
        SELECT jsonb_array_elements_text(c.info -> 'orders') AS order_id
    ) o
GROUP BY c.id, c.info ->> 'name';

Resultado:

id | customer_name | orders
---+---------------+----------
2  | Bob Johnson   | ["101", "102", "103"]

Consideraciones de rendimiento

Cuando trabajes con JSON en PostgreSQL, ten en cuenta estas consideraciones de rendimiento:

  1. Usa jsonb en lugar de json: el tipo jsonb ofrece mejor rendimiento en la mayoría de las operaciones.

  2. Indexa con estrategia: usa índices GIN para consultas de contención, pero crea índices específicos para los campos que consultas con frecuencia.

  3. Piensa bien la desnormalización: aunque JSON te permite desnormalizar tu modelo de datos, anidar en exceso puede afectar el rendimiento de las consultas.

  4. Vigila tus patrones de consulta: las expresiones de ruta JSON complejas o desanidar arrays grandes con frecuencia pueden ser operaciones costosas.

  5. Limita el tamaño de los arrays: los arrays JSON muy grandes pueden causar problemas de rendimiento al desanidarlos.

  6. Usa proyección: extrae solo los campos que necesitas en lugar de devolver el documento JSON completo.

Conclusión

Las capacidades JSON de PostgreSQL lo convierten en una excelente opción para aplicaciones que necesitan almacenar y consultar datos semiestructurados. Con los operadores y funciones de este tutorial, puedes trabajar con datos JSON de forma eficaz sin dejar de aprovechar la potencia y confiabilidad de una base de datos relacional madura.

Para modelos de datos complejos, considera un enfoque híbrido: usa tablas estructuradas para esquemas fijos y datos que consultas con frecuencia, y usa JSON para datos flexibles sin esquema o estructuras anidadas que serían difíciles de modelar de forma relacional.

¿Listo para probar estos ejemplos tú mismo? Abre Beekeeper Studio y empieza hoy a explorar las capacidades JSON de PostgreSQL.

Beekeeper Studio es un cliente de bases de datos gratuito y de código abierto

La mejor herramienta de consultas y edición de SQL que he usado. Tiene todo lo que necesito para administrar mi base de datos. - ⭐⭐⭐⭐⭐ Mit

Beekeeper Studio es rápido, intuitivo y fácil de usar. Es compatible con muchísimas bases de datos y funciona de maravilla en Windows, Mac y Linux.

La versión de Beekeeper para Linux tiene el 100% de las funciones, sin recortes ni concesiones.

Lo que dicen los usuarios de Beekeeper Studio

★★★★★
"Beekeeper Studio reemplazó por completo mi antiguo flujo de trabajo con SQL. Es rápido, intuitivo y hace que trabajar con bases de datos vuelva a ser agradable."
— Alex K., desarrollador de bases de datos
★★★★★
"He probado muchas GUI de bases de datos, pero Beekeeper logra el equilibrio perfecto entre funciones y simplicidad. Simplemente funciona."
— Sarah M., ingeniera Full Stack

¿Listo para mejorar tu flujo de trabajo con SQL?

download Descarga gratis