sqlpostgresqljsonbjson

to_jsonb no PostgreSQL: transformar uma linha inteira em objeto JSON

Como to_jsonb converte qualquer valor, linha ou array em jsonb preservando os tipos, e como difere de json_build_object e row_to_json.

3 min de leituraReferencesql · postgresql · jsonb · json · row_to_json

Quando voce precisa expor uma linha de tabela como JSON ou montar uma estrutura aninhada para uma API, o PostgreSQL oferece to_jsonb. Ele pega qualquer valor SQL, linha ou array e o transforma em jsonb sem perder os tipos. Vamos ver como usa-lo e como ele se compara a json_build_object e row_to_json.

O que o to_jsonb faz

to_jsonb(value) converte um unico valor em jsonb. Escalares viram escalares JSON, arrays viram arrays JSON e uma linha de tabela vira um objeto JSON cujas chaves sao os nomes das colunas:

-- Scalars and arrays keep their natural JSON shape
SELECT to_jsonb(42)                AS num,
       to_jsonb('hello'::text)     AS str,
       to_jsonb(ARRAY[1, 2, 3])    AS arr,
       to_jsonb(true)              AS flag;

O truque mais util e passar uma linha inteira. Um alias de tabela dentro de to_jsonb se refere a linha toda:

-- A whole row becomes one JSON object: column -> value
SELECT to_jsonb(u) AS user_json
FROM users u
WHERE u.country = 'DE';

Cada linha sai assim: {"id": 7, "email": "a@b.de", "name": "Anna", "country": "DE", "created_at": "2026-01-10T08:00:00"}. Repare que created_at e serializado como string ISO, os numeros continuam numeros e NULL vira null de JSON.

Os tipos sao preservados, e isso importa

O to_jsonb respeita os tipos de origem. Um inteiro continua numero, nao string; um booleano continua um true/false de verdade. Isso o distingue da concatenacao manual de texto:

SELECT jsonb_typeof(to_jsonb(o.amount))  AS amount_kind,   -- number
       jsonb_typeof(to_jsonb(o.status))  AS status_kind,   -- string
       jsonb_typeof(to_jsonb(NULL::int)) AS null_kind       -- null
FROM orders o
LIMIT 1;
  • integer e numeric viram numeros JSON.
  • text, varchar, date, timestamp sao serializados como strings.
  • boolean continua booleano.
  • Arrays do PostgreSQL viram arrays JSON, com o aninhamento preservado.

Gotcha: um timestamp sem fuso horario e convertido sem o sufixo Z, enquanto timestamptz inclui o deslocamento. Se o frontend espera UTC estrito, converta a coluna para timestamptz antes.

Objetos aninhados e selecao de colunas

Muitas vezes voce nao quer a linha inteira -- quer escolher campos ou aninhar dados relacionados. Ha dois caminhos. O primeiro: construir o objeto a partir da linha e remover chaves indesejadas com -:

-- Drop sensitive or noisy keys from the row object
SELECT to_jsonb(u) - 'created_at' - 'id' AS public_user
FROM users u;

O segundo, bem mais comum na pratica, e aninhar os pedidos de um usuario como um array. O jsonb_agg agrega as linhas de pedidos, cada uma transformada em objeto via to_jsonb:

-- Nest each user's orders as an array of JSON objects
SELECT to_jsonb(u) || jsonb_build_object(
         'orders',
         (SELECT jsonb_agg(to_jsonb(o))
          FROM orders o
          WHERE o.user_id = u.id)
       ) AS user_with_orders
FROM users u;

O operador || mescla dois objetos jsonb, adicionando a chave orders ao objeto do usuario. E assim que se constroi uma arvore de qualquer profundidade.

to_jsonb versus json_build_object

Quando voce precisa de uma forma explicita -- outros nomes de chave, campos calculados, uma ordem fixa -- use json_build_object (ou jsonb_build_object). Voce lista os pares chave-valor na mao:

-- Explicit shape: rename keys and add a computed field
SELECT jsonb_build_object(
         'user_id',   u.id,
         'label',     u.name || ' <' || u.email || '>',
         'is_local',  u.country = 'DE'
       ) AS card
FROM users u;

Como escolher:

  • to_jsonb(row) -- quando voce quer o objeto como esta, com os nomes das colunas. Codigo minimo, a forma segue o esquema.
  • jsonb_build_object(...) -- quando precisa de uma forma exata: renomear, calcular, selecionar campos, ordem de chaves estavel.

Costumam ser combinados: voce monta a base com to_jsonb e depois adiciona chaves calculadas por cima com || e jsonb_build_object.

to_jsonb versus row_to_json

A funcao antiga row_to_json(row) faz quase a mesma coisa, mas retorna o tipo json, nao jsonb. A diferenca e fundamental. Os operadores de acesso ->, ->>, #> e #>> funcionam tanto em json quanto em jsonb, entao ler uma chave nao e o que os distingue. O que o json nao consegue fazer e o resto da caixa de ferramentas:

  • json guarda o texto literal: preserva a ordem das chaves, duplicatas e espacos, mas nao suporta os operadores -, ||, @> (exclusivos de jsonb) nem indexacao GIN.
  • jsonb guarda uma forma binaria ja analisada: a ordem das chaves se perde, as duplicatas colapsam, mas voce ganha esses operadores extras e buscas indexadas rapidas.
-- Both json and jsonb support -> ; the jsonb-only operators are -, ||, @>
SELECT row_to_json(e)            AS as_json,
       to_jsonb(e)               AS as_jsonb,
       to_jsonb(e) -> 'salary'   AS salary_node   -- -> works on json too
FROM employees e
WHERE e.dept = 'eng';

Regra pratica: para codigo novo use to_jsonb, porque jsonb se manipula com os operadores extras, se indexa com GIN e e mais rapido de consultar. Deixe row_to_json para os casos em que a saida textual exata importa.

No MySQL o analogo mais proximo e JSON_OBJECT('k', v, ...), parecido com jsonb_build_object; nao existe um "linha inteira para JSON" direto, entao voce lista as chaves na mao. No ClickHouse o modelo JSON e diferente: ha um tipo JSON e uma funcao toJSONString, mas a semantica de "linha como objeto" difere, entao as consultas nao se transferem uma a uma.

Pratique com exercícios reais

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

Abrir o treinador