🧚 Escute! O Beekeeper Studio é uma GUI de banco de dados rápida, moderna e open source Baixar
23 de março de 2025 Por Matthew Rathbone

O PostgreSQL oferece suporte poderoso para armazenar e consultar dados JSON por meio dos tipos de dados json e jsonb. O tipo jsonb é especialmente útil porque armazena os dados em formato binário, permitindo indexação e consultas mais eficientes em comparação com o tipo json, baseado em texto.

Neste tutorial, vamos explorar as operações JSON mais comuns no PostgreSQL com exemplos práticos que você pode usar nas suas aplicações.

Criando dados JSON

Vamos começar criando uma tabela com uma coluna jsonb e inserindo alguns dados de exemplo:

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]}'
);

Operações JSON básicas

Recuperando o documento JSON inteiro

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"}
  ]
}

Extraindo valores do JSON

O PostgreSQL oferece vários operadores para extrair valores do JSON:

Extraindo um campo específico com o operador -> (retorna JSON)

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

Resultado:

"Alice Smith"
"Bob Johnson"

Extraindo um campo específico com o operador -» (retorna texto)

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

Resultado:

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

Acessando objetos aninhados

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

Resultado:

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

Usando o operador #> para acesso por caminho

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

Resultado:

"San Francisco"
"Seattle"

Usando o operador #» para acesso por caminho 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

Modificando dados JSON

O PostgreSQL oferece várias funções para modificar dados JSON:

Adicionando um campo com jsonb_set

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

Removendo um campo com o operador -

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

Mesclando objetos JSON com ||

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

Atualizando um campo aninhado

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

Consultando arrays JSON

Trabalhar com arrays JSON é uma operação comum:

Obtendo o tamanho do 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

Extraindo elementos específicos do 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"}

Desaninhando arrays para consultar elementos individuais

-- 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"}

Filtrando com arrays desaninhados

-- 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

Verificando chaves e valores

Verificando se uma chave existe

-- 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

Verificando valores em 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

Verificando se algum elemento do array corresponde

-- 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

Indexando dados JSON

Em bancos de dados de produção com grandes volumes de dados JSON, uma indexação adequada é essencial:

Criando um índice GIN para consultas de contenção

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

Criando um índice específico para um campo JSON

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

Usando campos indexados em 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';

Convertendo entre JSON e tabelas

Convertendo JSON em linhas (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

Convertendo arrays aninhados em tabelas (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

Convertendo resultados de consultas em 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"]

Considerações de desempenho

Ao trabalhar com JSON no PostgreSQL, tenha em mente estas considerações de desempenho:

  1. Use jsonb em vez de json: o tipo jsonb oferece melhor desempenho na maioria das operações.

  2. Indexe de forma estratégica: use índices GIN para consultas de contenção, mas crie índices específicos para campos consultados com frequência.

  3. Pense bem antes de desnormalizar: embora o JSON permita desnormalizar seu modelo de dados, aninhamento excessivo pode afetar o desempenho das consultas.

  4. Observe os padrões de consulta: expressões de caminho JSON complexas ou o desaninhamento frequente de arrays grandes podem ser operações custosas.

  5. Limite o tamanho dos arrays: arrays JSON muito grandes podem causar problemas de desempenho ao serem desaninhados.

  6. Considere a projeção: extraia apenas os campos de que você precisa em vez de retornar o documento JSON inteiro.

Conclusão

Os recursos de JSON do PostgreSQL fazem dele uma excelente escolha para aplicações que precisam armazenar e consultar dados semiestruturados. Com os operadores e funções abordados neste tutorial, você pode trabalhar com dados JSON de forma eficaz, aproveitando ao mesmo tempo o poder e a confiabilidade de um banco de dados relacional maduro.

Para modelos de dados complexos, considere uma abordagem híbrida: use tabelas estruturadas para esquemas fixos e dados consultados com frequência, e use JSON para dados flexíveis, sem esquema, ou estruturas aninhadas que seriam difíceis de modelar de forma relacional.

Pronto para testar esses exemplos? Abra o Beekeeper Studio e comece hoje mesmo a explorar os recursos de JSON do PostgreSQL.

Beekeeper Studio é um cliente de banco de dados gratuito e open source

A melhor ferramenta de consultas e edição de SQL que já usei. Tem tudo o que preciso para gerenciar meu banco de dados. - ⭐⭐⭐⭐⭐ Mit

O Beekeeper Studio é rápido, intuitivo e fácil de usar. Ele suporta vários bancos de dados e funciona muito bem no Windows, Mac e Linux.

A versão do Beekeeper para Linux tem 100% dos recursos, sem atalhos e sem concessões.

O que os usuários dizem sobre o Beekeeper Studio

★★★★★
"O Beekeeper Studio substituiu completamente meu antigo fluxo de trabalho com SQL. É rápido, intuitivo e torna o trabalho com bancos de dados agradável de novo."
— Alex K., desenvolvedor de banco de dados
★★★★★
"Já testei muitas GUIs de banco de dados, mas o Beekeeper encontra o equilíbrio perfeito entre recursos e simplicidade. Simplesmente funciona."
— Sarah M., engenheira full stack

Pronto para melhorar seu fluxo de trabalho com SQL?

download Baixar grátis