Como achatar JSON aninhado em CSV: 5 estratégias e matriz de decisão
O problema é de geometria
Você bate na mesma parede toda vez. Uma API devolve JSON aninhado e o analista no Slack só quer uma planilha. O mongoexport cospe wrappers $oid e três níveis de metadados, enquanto o BigQuery espera uma tabela plana. Achatar JSON aninhado em CSV não é um problema de sintaxe. É um problema de geometria. JSON é uma árvore, CSV é uma grade, e você não move uma árvore para dentro de uma grade sem decidir como os galhos colapsam.
Existem exatamente cinco estratégias de colapso. Escolha a errada e você entrega 200 colunas para o Excel, perde precisão num ID do Twitter ou quebra o round-trip do qual seu pipeline depende. Escolha a certa e a conversão vira uma linha só.
| Estratégia | Em uma linha | Ideal para |
|---|---|---|
| Notação de pontos | customer.address.city | Análise em Excel/Sheets |
| Underscore | customer_address_city | Colunas amigáveis para SQL |
| Arrays indexados | items.0.sku, items.1.sku | Arrays de tamanho fixo |
| Explosão de linhas | Repete o pai para cada filho | Analytics em Pandas/BigQuery |
| Stringify | "{\"city\":\"Seattle\"}" em uma célula | Round-trip sem perdas |
Este guia percorre cada estratégia, entrega uma matriz de decisão indexada pelo consumidor (Excel, Pandas, BigQuery, Postgres) e mostra quatro payloads reais em que a estratégia certa não é a óbvia. Se você também precisa da visão bidirecional geral (bibliotecas de parser, streaming, armadilhas de codificação), consulte o CSV para JSON: Métodos, erros comuns.
Por que JSON aninhado não cabe em CSV
JSON carrega três tipos de estrutura que faltam ao CSV. Hierarquia é um objeto dentro de outro objeto. Sequência é um array. Misto é a combinação: arrays de objetos, objetos com arrays, arrays de arrays. Um pedido típico de e-commerce é os três ao mesmo tempo.
CSV tem exatamente duas dimensões: linhas e colunas. Não existe um terceiro eixo para “esta coluna guarda três filhos.” Quando você exige uma grade a partir de uma árvore, algo precisa ceder. Ou você espalha os filhos por mais colunas (e convive com nomes como items.0.options.0.value), ou os espalha por mais linhas (campos do pai se repetem), ou os comprime em uma célula como texto e para de tratá-los como estrutura.
Cada estratégia abaixo responde a essa pergunta de maneira diferente. Algumas preservam a legibilidade e perdem segurança de round-trip. Outras fazem o contrário. Nenhuma é universal. Combine a resposta com quem vai ler o arquivo em seguida.
5 estratégias de achatamento comparadas
Estratégia 1: Notação de pontos (customer.address.city)
A notação de pontos caminha da raiz à folha e usa . para juntar as chaves. Cada objeto aninhado vira uma coluna por folha, com o caminho codificado no nome da coluna.
{ "customer": { "address": { "city": "Seattle" } }, "email": "alice@example.com" }
vira
customer.address.city,email
Seattle,alice@example.com
No Pandas, uma linha resolve:
import pandas as pd
data = [{"customer": {"address": {"city": "Seattle"}}, "email": "alice@example.com"}]
df = pd.json_normalize(data, sep='.')
df.to_csv("out.csv", index=False)
Em JavaScript, uma pequena função recursiva basta:
function flattenDot(obj, prefix = '', acc = {}) {
for (const [k, v] of Object.entries(obj)) {
const key = prefix ? `${prefix}.${k}` : k;
if (v && typeof v === 'object' && !Array.isArray(v)) {
flattenDot(v, key, acc);
} else {
acc[key] = v;
}
}
return acc;
}
Prós: legível por humanos, padrão do Pandas, preserva o caminho original. Contras: nomes de coluna podem ficar longos (specs do Kubernetes geram nomes como spec.template.spec.containers.0.resources.limits.memory), e o ponto fica ambíguo se uma chave real contiver . (parâmetros de evento do Google Analytics 4 contêm).
Estratégia 2: Notação com underscore (customer_address_city)
Mesma ideia, separador diferente. Troque . por _ e o resultado fica SQL-safe: SELECT customer_address_city FROM events funciona sem precisar colocar o identificador entre aspas. BigQuery, Snowflake e Postgres todos preferem essa forma.
import pandas as pd
df = pd.json_normalize(data, sep='_')
A decisão entre ponto e underscore é puramente sobre a ferramenta a jusante. Analistas de Excel leem ponto com mais naturalidade; engines SQL aceitam underscore sem reclamar. Troque mudando um único argumento.
Prós: nomes de coluna SQL-safe, identificadores compatíveis com BigQuery, sem aspas. Contras: a ambiguidade persiste se uma chave contiver _ (menos comum que ., mas ainda possível).
Estratégia 3: Arrays indexados (items.0.sku, items.1.sku)
Objetos achatam de maneira limpa porque chaves são únicas. Arrays não, porque o comprimento é ilimitado. A estratégia indexada trata posições do array como segmentos do caminho: items[0] vira items.0.
{ "id": "ord-001", "items": [{"sku": "A"}, {"sku": "B"}] }
vira
id,items.0.sku,items.1.sku
ord-001,A,B
Esse é o comportamento padrão do Flatten no nosso Conversor JSON para CSV. Cada folha ganha sua própria coluna; a posição é registrada no nome.
Prós: cada valor ganha sua célula, posição preservada, sem duplicação de linhas. Contras: a contagem de colunas explode (100 itens = 100 colunas); linhas com arrays de tamanhos diferentes produzem tabelas irregulares; agregações a jusante quebram (sem SUM(items.*.qty)).
Estratégia 4: Explosão de linhas (array para múltiplas linhas)
Em vez de alargar a tabela para acomodar o array, alongue-a. Repita os campos do pai uma vez por elemento do array, e deixe cada elemento virar sua própria linha.
{ "order_id": "ord-001", "customer": "Alice", "items": [{"sku": "A", "qty": 2}, {"sku": "B", "qty": 1}] }
vira
order_id,customer,items.sku,items.qty
ord-001,Alice,A,2
ord-001,Alice,B,1
No Pandas, uma linha faz tanto a explosão quanto a normalização:
import pandas as pd
orders = [{"order_id": "ord-001", "customer": "Alice",
"items": [{"sku": "A", "qty": 2}, {"sku": "B", "qty": 1}]}]
df = pd.json_normalize(orders, record_path='items', meta=['order_id', 'customer'])
df.to_csv("orders.csv", index=False)
Em SQL, UNNEST faz o mesmo:
SELECT order_id, item.sku, item.qty FROM orders, UNNEST(items) AS item;
Prós: Pandas e BigQuery tratam essa forma nativamente, agregações funcionam (GROUP BY order_id), o esquema permanece estreito. Contras: campos do pai se duplicam em cada linha filha (inchaço de armazenamento), a fronteira 1-para-muitos fica implícita (você precisa de um order_id), e dois arrays no mesmo nível produzem um produto cartesiano a menos que você faça UNNEST deles com cuidado.
Estratégia 5: Stringify (JSON dentro da célula)
A opção radical: não achate nada. Serialize o valor aninhado inteiro como uma string JSON e coloque em uma única célula. A tabela externa permanece plana; a estrutura é preservada literalmente por dentro.
{ "id": "ord-001", "items": [{"sku": "A"}, {"sku": "B"}] }
vira
id,items
ord-001,"[{""sku"":""A""},{""sku"":""B""}]"
Esse é o modo Stringify no nosso Conversor JSON para CSV. A contagem de colunas nunca explode, a forma original é preservada byte a byte, e o caminho de volta reconstrói a entrada exatamente.
Prós: 100% sem perdas, contagem de colunas previsível, round-trip seguro quando combinado com Infer types na volta. Contras: usuários do Excel veem aspas escapadas, engines SQL precisam de funções JSON para consultar dentro do valor (JSON_EXTRACT_SCALAR no BigQuery, ->>'key' no Postgres), e fórmulas de planilha não conseguem alcançar o conteúdo da célula.
As 5 estratégias lado a lado
Mesma entrada nas cinco: {"id":"ord-001","customer":{"name":"Alice"},"items":[{"sku":"A","qty":2},{"sku":"B","qty":1}]}.
| Estratégia | Colunas | Round-trip seguro | Melhor consumidor |
|---|---|---|---|
| Notação de pontos | cresce com o array | Não | Analista de Excel |
| Underscore | cresce com o array | Não | Data warehouse SQL |
| Arrays indexados | 2 por slot do array | Não (ambíguo na volta) | Arrays de tamanho fixo |
| Explosão de linhas | estreito, 1 linha por filho | Parcial (precisa de chave) | Pandas / BigQuery |
| Stringify | fixo | Sim | Round-trip de pipeline |
Matriz de decisão: qual estratégia para qual consumidor
Procure primeiro o consumidor, depois leia a estratégia recomendada.
| Consumidor | Estratégia recomendada | Por quê |
|---|---|---|
| Excel / Sheets (analista) | Pontos + Stringify para arrays grandes | Nomes de coluna legíveis; arrays grandes não explodem a planilha |
| Excel-EU (DE/FR/IT/ES) | Pontos + delimitador ; + UTF-8 BOM | Ponto e vírgula obrigatório; BOM evita confusão de codificação |
Pandas (json_normalize + explode) | Underscore + explosão de linhas | Colunas amigáveis para SQL; o explode combina bem com groupby |
| BigQuery / Snowflake | TSV + Stringify ou explosão | Tab evita armadilhas de aspas; JSON_EXTRACT consulta a célula |
COPY do PostgreSQL | RFC 4180 + underscore + plano | Colunas SQL-safe; aspas RFC estritas |
| ETL MongoDB → BigQuery | Carregar NDJSON direto, pular CSV | BigQuery carrega NDJSON nativamente; CSV é um desvio |
Excel / Google Sheets: a armadilha do locale
Nomes de coluna do Excel não têm limite prático de tamanho. As armadilhas reais são três.
Primeira, o split de locale. O Excel europeu (Alemanha, França, Itália, Espanha) espera ; como delimitador porque a , é o separador decimal. Um CSV separado por vírgulas abre com todas as linhas colapsadas na coluna A. O preset Excel da nossa ferramenta json-para-csv troca para ; + CRLF + UTF-8 BOM em um clique.
Segunda, notação científica. O Excel enxerga 9007199254740993 e renderiza 9.00719925474E+15. Armazene inteiros grandes como strings no JSON de origem e ligue o BOM para que o Excel mantenha a célula como texto. Nosso conversor detecta inteiros grandes automaticamente.
Terceira, o limite prático de colunas. O Excel suporta 16.384 colunas em tese, mas qualquer coisa acima de ~500 vira inviável. Faça Stringify nas sub-árvores pesadas ou pré-projete com jq antes de converter.
Pandas: json_normalize + explode
O padrão comum para arrays aninhados é record_path + meta numa só passada:
import pandas as pd
orders = [{
"order_id": "ord-001",
"customer": {"name": "Alice", "city": "Seattle"},
"items": [{"sku": "SKU-100", "qty": 2}, {"sku": "SKU-205", "qty": 1}]
}]
df = pd.json_normalize(orders, record_path='items',
meta=['order_id', ['customer', 'name'], ['customer', 'city']], sep='_')
df.to_csv("orders.csv", index=False)
A saída é uma linha por item, com order_id, customer_name e customer_city repetidos. Isso supera rodar explode primeiro e json_normalize depois: record_path pula a coluna intermediária de objeto e meta permite controlar quais campos do pai propagam. Para entradas em que elementos do array contêm objetos aninhados, defina max_level= para limitar a profundidade.
BigQuery / Snowflake: TSV + JSON dentro da célula
O LOAD DATA do BigQuery é rigoroso com aspas em CSV e frequentemente interpreta mal arquivos com vírgulas dentro de texto entre aspas. TSV é mais seguro porque tabulações quase nunca aparecem em campos de texto:
bq load --source_format=CSV --field_delimiter='\t' \
dataset.orders gs://bucket/orders.tsv \
order_id:STRING,customer:STRING,items:STRING
Quando você carrega dados aninhados como JSON Stringified em uma única coluna, o BigQuery ainda consulta para dentro com JSON_EXTRACT_SCALAR:
SELECT order_id, JSON_EXTRACT_SCALAR(items, '$[0].sku') AS first_sku
FROM dataset.orders;
O Snowflake oferece o mesmo recurso via VARIANT, com consultas de caminho como items:0.sku::STRING. Em ambos os engines, Stringify + consultas de path JSON ganha do achatamento completo quando arrays aninhados são grandes ou têm tamanho variável.
COPY do PostgreSQL: RFC 4180 estrito
COPY ... FROM ... WITH (FORMAT csv, HEADER true) é o leitor RFC 4180 mais estrito que você costuma encontrar. Dois comportamentos derrubam quem o usa.
Primeiro, o COPY não aceita UTF-8 BOM. A marca de ordem de bytes vira um prefixo literal no primeiro nome de coluna (id em vez de id), e toda consulta que referencia id falha silenciosamente. Desligue o BOM para alvos Postgres.
Segundo, o COPY não consegue parsear dados aninhados nativamente. Ou exploda os arrays em múltiplas linhas antes da carga, ou defina o destino como jsonb e faça stringify do valor aninhado:
CREATE TABLE orders (order_id text PRIMARY KEY, customer text, items jsonb);
COPY orders FROM '/tmp/orders.csv' WITH (FORMAT csv, HEADER true);
SELECT order_id, items->0->>'sku' AS first_sku FROM orders;
Para pipelines que já falam JSON de ponta a ponta, pule o CSV e use COPY ... FROM ... WITH (FORMAT text) com entrada JSON-line.
Passo a passo com payloads reais
Passo a passo 1: Pedidos de e-commerce (cliente + array de itens)
Um pedido típico combina informações aninhadas do cliente com um array de itens de tamanho variável:
[{ "id": "ord-001",
"customer": { "name": "Alice", "address": {"city": "Seattle", "country": "US"} },
"items": [{"sku": "SKU-100", "qty": 2}, {"sku": "SKU-205", "qty": 1}] }]
A estratégia certa depende de quem lê o arquivo. Finanças quer uma linha por item para computar receita por SKU; é a estratégia de explosão, produzindo duas linhas com id e customer.name repetidos. Operações quer uma linha por pedido para dashboards de fulfillment; é a notação de pontos com items Stringified para que o array não estoure a contagem de colunas. Mesma entrada, duas saídas, ambas corretas para seu consumidor.
Teste direto: cole o payload no nosso Conversor JSON para CSV e alterne Flatten contra Stringify na opção Nested. O exemplo “Nested E-commerce Orders” carrega exatamente essa forma.
Passo a passo 2: API de issues do GitHub (array labels + objeto user)
O endpoint /repos/{owner}/{repo}/issues devolve uma forma aninhada mista:
[{ "id": 1001, "title": "Bug: login 404", "state": "open",
"labels": ["bug", "priority:high"], "user": {"login": "alice"} }]
user é um objeto com um campo útil; labels é um array de strings de tamanho ilimitado. O achatamento pragmático é híbrido: notação de pontos em user (você só se importa com user.login), e inline-join em labels para uma única célula separada por ;:
id,title,state,labels,user.login
1001,Bug: login 404,open,bug;priority:high,alice
Você não captura “juntar arrays numa célula” e “achatar objetos com pontos” numa estratégia única. Nosso conversor cuida do achatamento de objetos automaticamente; pré-processe as labels com jq (map(.labels = (.labels | join(";")))) ou aceite o comportamento padrão de array-stringify.
Passo a passo 3: MongoDB mongoexport ($oid + metadados)
mongoexport --jsonArray produz wrappers Extended JSON:
[{ "_id": {"$oid": "6634a1b2c3d4e5f600000001"},
"email": "alice@example.com",
"metadata": { "signupDate": "2026-01-15T10:30:00Z",
"preferences": {"newsletter": true, "theme": "dark"} } }]
O wrapper $oid gera uma coluna literalmente chamada _id.$oid, que a maioria dos engines SQL rejeita. Pré-processe com jq para desembrulhar:
mongoexport --collection=users --jsonArray | jq 'map(._id = ._id."$oid")' > users.json
Para o bloco profundamente aninhado metadata.preferences, escolha pelo consumidor. Export analítico: achate tudo com pontos; metadata.preferences.theme lê bem. Round-trip de pipeline: faça stringify de metadata para manter a estrutura intacta. Para padrões completos de jq que se encaixam em pipelines CSV, veja nosso Guia rápido do jq.
Passo a passo 4: Pod Spec do Kubernetes (profundamente aninhado)
Uma resposta de kubectl get pod -o json é o pior caso para estratégias planas. A estrutura desce rotineiramente seis níveis (spec.template.spec.containers.0.resources.limits.memory). O achatamento ingênuo com pontos gera nomes de coluna que ultrapassam 70 caracteres e 200+ colunas de saída. Duas estratégias funcionam.
Pré-projete com kubectl jsonpath. Selecione apenas os campos que você realmente precisa:
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\t"}{.status.phase}{"\n"}{end}' > pods.tsv
Stringify o spec, achate os metadata. Mantenha metadata (name, namespace, labels) plano e faça stringify de spec em uma única célula:
kubectl get pods -o json | jq 'map({name: .metadata.name, namespace: .metadata.namespace, spec: (.spec | tostring)})'
Depois cole no conversor com o modo Flatten. A coluna spec vira uma célula JSON; as colunas de metadata permanecem legíveis. Evite o anti-padrão kubectl get pod -o json | json-to-csv flatten sem pré-projeção. A contagem de colunas será inviável.
Segurança de round-trip: achatar perde, Stringify preserva
Existe um teorema que guias concorrentes pulam. Notação de pontos, notação underscore, arrays indexados e explosão de linhas são todas projeções de mão única. Uma vez que você achatou com qualquer uma, o JSON original não pode ser perfeitamente reconstruído a partir do CSV sozinho.
Contraexemplos são fáceis de construir. Uma coluna chamada customer.address.city é ambígua entre {"customer": {"address": {"city": "..."}}} e {"customer": {"address.city": "..."}}. Arrays indexados parecem reversíveis, mas o CSV não sabe dizer se items.0.sku deveria reconstruir para um array ou para um objeto com chave numérica. A explosão de linhas exige uma chave de group-by; sem order_id, você não consegue dizer quais linhas pertenciam ao mesmo pai.
Apenas o Stringify sobrevive ao round-trip. O valor aninhado é preservado verbatim como string JSON, então o conversor reverso lê a célula, parseia e reinsere o original intacto. Converta com Stringify, salve o CSV, cole no nosso Conversor CSV para JSON, ligue Infer types, e você obtém bytes idênticos à entrada.
A regra prática: round-trip de pipeline → Stringify. Análise ou relatório pontuais → pontos, underscore ou explosão, conforme o consumidor.
Fazendo na nossa ferramenta no navegador
O Conversor JSON para CSV expõe duas das cinco estratégias diretamente: Flatten (combinando notação de pontos e arrays indexados) e Stringify (preservando estrutura dentro de uma célula). As outras três (underscore, explosão de linhas, presets de alvo SQL) ficam a um passo de pré-processamento.
Uma sessão típica leva cinco cliques:
- Valide a entrada com nosso Formatador JSON para que erros de sintaxe não virem falhas silenciosas de conversão.
- Cole o JSON no Conversor JSON para CSV. A conversão roda na hora.
- Coloque Nested em Flatten para chaves pontuadas e indexadas, ou em Stringify para manter arrays e objetos em células únicas.
- Escolha um preset: RFC 4180 para pipelines, Excel para planilhas EU, TSV para warehouses, Pipe para textos com muitas vírgulas.
- Clique em Swap direction e use o Conversor CSV para JSON com Infer types ligado para verificar um round-trip Stringify.
Tudo roda no seu navegador. PII, exports internos e segredos de produção nunca saem da página; zero requisições de rede depois que a página carrega. Isso funciona quando subir os dados para um site terceiro não é uma opção.
Armadilhas comuns
Seis modos de falha aparecem repetidamente.
- Explosão de nomes de coluna. Specs do Kubernetes e threads de revisão de PR do GitHub geram centenas de caminhos-folha. Solução: pré-projete com
jqoukubectl jsonpath, ou faça stringify das sub-árvores pesadas enquanto achata os metadados. - Mismatch no tamanho do array. A linha 1 tem 3 itens, a linha 2 tem 5. Arrays indexados geram células em branco em
items.3.skueitems.4.skupara a linha 1. Solução: troque para explosão de linhas. - Chaves de índice tratadas como strings na volta. Quando o CSV-to-JSON vê
items.0.sku, o0é tecnicamente uma chave string. Alguns conversores reversos reconstroem{"0": {"sku": "A"}}em vez de[{"sku": "A"}]. Solução: use Stringify para round-trips. - Chaves que já contêm o separador. Eventos do GA4 têm chaves como
event_params.keycom pontos literais; achatar com.gera caminhos ambíguos. Solução: use underscore, ou renomeie as chaves problemáticas. Veja nosso De JSON5 a JSONC para o pano de fundo sobre formatos JSON com suporte a chaves estendido. - Tipos misturados entre níveis. Algumas linhas têm
addresscomo objeto, outras comonull. O achatamento gera células vazias onde o objeto era nulo. O aviso de notas de schema no nosso conversor sinaliza isso para que você verifique o consumidor a jusante. - Inteiros grandes truncados pelo Excel. Um Long de
$oid, um snowflake ID do Twitter ou umresourceVersiondo K8s ultrapassa o intervalo seguro do JavaScript (2^53 - 1) e é arredondado em silêncio. O Excel então os renderiza como9.00719925474E+15. Solução: armazene IDs como strings no JSON de origem, habilite BOM e use o preset Excel.
FAQ
Qual é a melhor maneira de achatar JSON aninhado em CSV?
A melhor maneira de achatar JSON aninhado em CSV depende do consumidor a jusante. Use notação de pontos para Excel ou Google Sheets. Use explosão de linhas quando Pandas ou BigQuery forem agregar os dados. Use Stringify quando o CSV precisar voltar para JSON sem perda. Combine a estratégia com o próximo leitor.
Como converto um array JSON em múltiplas linhas CSV?
Converta um array JSON em múltiplas linhas CSV usando a estratégia de explosão: duplique os campos do pai uma vez por elemento do array para que cada elemento vire sua própria linha. No Pandas, pd.json_normalize(data, record_path='items', meta=['order_id']) faz isso numa única chamada. Em SQL, UNNEST(items) produz a mesma forma. As chaves do pai se repetem nas linhas explodidas.
Posso fazer round-trip do CSV de volta para o JSON aninhado original?
O round-trip do CSV de volta para o JSON aninhado original só funciona com o modo Stringify. Notação de pontos, underscore, arrays indexados e explosão de linhas são projeções de mão única com perdas; o conversor reverso não consegue reconstruir a árvore perfeitamente. O Stringify preserva arrays e objetos como JSON dentro de uma única célula, então o round-trip completo fica byte a byte idêntico quando Infer types está ligado.
Por que o Excel mostra meu JSON achatado como uma única coluna longa?
O Excel mostra seu JSON achatado como uma única coluna longa quando você está num locale europeu (Alemanha, França, Itália, Espanha), onde a vírgula é reservada para decimais e o Excel espera ponto e vírgula como delimitador. O preset Excel em json-para-csv troca para ; + CRLF + UTF-8 BOM em um clique.
Devo usar notação de pontos ou underscore para nomes de coluna?
Use notação de pontos quando o alvo for Excel, Google Sheets ou Pandas; pontos são o padrão de json_normalize e leem com naturalidade. Use underscore quando o alvo for SQL: Postgres, BigQuery e Snowflake exigem aspas em torno de identificadores que contêm pontos, enquanto underscores são aceitos sem aspas em qualquer lugar.
Como o pandas json_normalize lida com arrays de objetos?
O json_normalize do Pandas lida com arrays de objetos por meio dos argumentos record_path e meta. pd.json_normalize(data, record_path='items', meta=['order_id']) explode items em uma linha por elemento com order_id repetido. Para objetos aninhados sem arrays, o mais simples pd.json_normalize(data, sep='_') gera nomes de coluna separados por underscore como customer_address_city. Use max_level= para limitar a profundidade em árvores profundas.
Qual o limite de colunas ao achatar JSON profundamente aninhado?
O limite de colunas ao achatar JSON profundamente aninhado é de 16.384 no Excel e praticamente ilimitado no CSV em si, mas passando de 500 colunas a saída fica inviável. Specs de Pod do Kubernetes ou respostas GraphQL ultrapassam isso facilmente. Faça stringify nas sub-árvores pesadas com o Conversor JSON para CSV ou pré-projete com jq ou kubectl jsonpath.
O jq é uma boa ferramenta para achatar JSON antes da conversão para CSV?
Sim, o jq é a ferramenta certa para achatar JSON antes da conversão para CSV. Ele cuida de pré-projeção (map({id, name})), pré-explosão (.[] | {id, item: .items[]}) e normalização de forma em uma linha. O pipeline jq roda antes da etapa CSV e controla exatamente quais campos chegam ao conversor. Veja nosso Guia rápido do jq para padrões.
Conclusão
Cinco lições para levar:
- JSON-para-CSV é um problema de geometria, não de sintaxe. Uma árvore não cabe numa grade sem escolher como os galhos colapsam.
- Cinco estratégias cobrem o universo prático (pontos, underscore, arrays indexados, explosão de linhas, Stringify). Escolha pelo consumidor.
- Stringify é o único caminho sem perdas. Use para round-trips de pipeline.
- Excel-EU e BigQuery têm presets por um motivo. Use.
- Payloads reais (mongoexport, specs do Kubernetes, respostas do GitHub) normalmente exigem uma etapa de pré-projeção com
jqoukubectl jsonpathantes.
Teste seu próprio payload no Conversor JSON para CSV. Roda localmente, cobre as cinco estratégias e faz round-trip sem perdas com Stringify. Nenhum upload, nenhum cadastro, e os dados ficam na página.