sqlpostgresqljsonbjson

Operadores seta do JSONB: -> e ->> no PostgreSQL

Como funcionam -> e ->>: ler campos de objeto e elementos de array, descer por estruturas aninhadas encadeando e converter o resultado ao tipo certo.

2 min de leituraReferencesql · postgresql · jsonb · json · mysql · clickhouse

Quando voce guarda dados semiestruturados em uma coluna JSONB, toda leitura comeca com dois operadores: -> e ->>. Eles sao a base de qualquer consulta JSON no PostgreSQL: um desce pela estrutura e o outro extrai um valor pronto para usar. Vamos ver como diferem, como acessar campos de objeto e elementos de array e como encadea-los.

-> retorna jsonb, ->> retorna text

Os dois operadores buscam um valor por chave, mas retornam tipos diferentes. -> entrega jsonb (um objeto, array ou escalar em forma JSON), enquanto ->> entrega text puro. Essa unica diferenca determina todo o resto.

-- prefs is a jsonb column on users: {"theme": "dark", "lang": "en"}
SELECT
  prefs -> 'theme'  AS as_jsonb,   -- "dark"  (with quotes, type jsonb)
  prefs ->> 'theme' AS as_text     -- dark    (no quotes, type text)
FROM users;

Uma regra simples:

  • Use -> quando for descer mais e ainda vier outro -> ou ->>.
  • Use ->> no fim do caminho, quando quiser um valor escalar para exibir ou comparar.

A chave e uma string (o nome de um campo do objeto), e uma chave inexistente retorna NULL em vez de um erro.

Campos de objeto e elementos de array

Se a direita do operador houver uma string, o PostgreSQL procura um campo do objeto. Se houver um inteiro, ele indexa um array, e a indexacao comeca em zero. Um indice negativo conta a partir do fim.

-- meta = {"tags": ["new", "vip", "eu"], "score": 7}
SELECT
  meta -> 'tags' -> 0     AS first_tag_json,   -- "new" as jsonb
  meta -> 'tags' ->> 0    AS first_tag_text,   -- new  as text
  meta -> 'tags' ->> -1   AS last_tag          -- eu   (last element)
FROM users;

O mesmo vale sobre suas proprias tabelas. Suponha que orders tenha um payload com um array de itens:

-- payload = {"items": [{"sku": "A1", "qty": 2}, {"sku": "B7", "qty": 1}]}
SELECT
  id,
  payload -> 'items' -> 0 ->> 'sku' AS first_sku
FROM orders
WHERE status = 'paid';

Encadeamento e conversao de tipos

Um caminho longo e apenas varios operadores em sequencia. Desca com ->, permanecendo em jsonb, e no ultimo passo troque para ->> para obter text. Como ->> sempre retorna texto, converta explicitamente com :: para numeros, datas e booleanos.

-- profile = {"address": {"city": "Berlin", "zip": "10115"}, "age": "34"}
SELECT
  profile -> 'address' ->> 'city'        AS city,
  (profile ->> 'age')::int               AS age_int
FROM users
WHERE (profile ->> 'age')::int >= 18;

Um exemplo real de agregacao: extrair um valor dos metadados JSON e calcular o ticket medio por pais.

-- payload = {"amount": "149.90", "currency": "EUR"}
SELECT
  u.country,
  round(avg((o.payload ->> 'amount')::numeric), 2) AS avg_amount
FROM orders o
JOIN users u ON u.id = o.user_id
GROUP BY u.country
ORDER BY avg_amount DESC;

Pegadinhas

  • Comparar sem converter quase sempre e um bug: payload ->> 'amount' > '99' compara strings lexicograficamente, entao '9' fica acima de '100'. Converta para numero: (payload ->> 'amount')::numeric > 99.
  • -> sobre um escalar retorna jsonb, entao prefs -> 'theme' = 'dark' falha com erro de tipo; use ->> para comparar ou escreva prefs -> 'theme' = '"dark"'::jsonb.
  • Uma chave inexistente ou um indice fora do intervalo retorna NULL em silencio, entao um erro de digitacao no nome de um campo nao gera erro e corrompe o resultado sem aviso.
  • ->> sobre um objeto ou array retorna o texto JSON completo, nao um unico valor; pegue texto apenas em escalares.

O MySQL nao tem esse encadeamento com setas: use JSON_EXTRACT(doc, '$.address.city') ou o atalho doc->>'$.address.city' (o ->> dele tambem retorna texto). O ClickHouse oferece funcoes como JSONExtractString(col, 'city') e JSONExtractInt(col, 'age'). A ideia e universal, mas a sintaxe de setas -> / ->> e propria do PostgreSQL.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador