NDJSON para JSON
Transforma registros separados por quebras de linha em um array, e aponta a linha que falha.
Nada do que você cola sai do seu navegador. A lista de permissões connect-src transforma isso em uma garantia do navegador, e não em uma promessa. Confira você mesmo
Transforme JSON delimitado por quebras de linha em um único array. Cada linha é parseada de forma independente, e qualquer linha que falhe é reportada com o número dela em vez de derrubar o arquivo inteiro.
NDJSON é o que sai de pipelines de log, de exportações do BigQuery, de arquivos bulk do Elasticsearch e de APIs em streaming, e é o que causa os erros "Extra data" e "unexpected non-whitespace character" quando alguém tenta parsear como um documento só.
O que é NDJSON
Um valor JSON completo por linha, separados por quebra de linha. Sem vírgulas entre registros, sem array envolvendo. Linhas em branco são ignoradas. As extensões convencionais são .ndjson e .jsonl.
JSON Lines e NDJSON são na prática o mesmo formato descrito por duas especificações pequenas que concordam em tudo que importa. Algumas ferramentas citam uma, outras citam a outra; um arquivo escrito para qualquer uma é lido corretamente pelas duas.
Por que ele existe
Três vantagens reais, todas vindas do fato de os registros serem independentes.
- Ele faz streaming
- Quem consome processa um registro por vez e nunca segura o arquivo inteiro. Uma exportação de 50 GB tudo bem; um array JSON de 50 GB não.
- Ele aceita append
- Acrescentar um registro é uma única escrita no fim do arquivo. Acrescentar a um array JSON significa reescrever o colchete de fechamento, o que não é append nenhum.
- Ele sobrevive a corrupção
- Uma linha malformada custa um registro. Um byte malformado em um array JSON custa o arquivo.
Para que lado converter
Para array quando os dados vão para algum lugar que espera um documento único: um navegador, um corpo de requisição, um arquivo de configuração. Para NDJSON quando vão para um pipeline, um log, um arquivo append-only ou qualquer coisa que faça streaming. As duas direções estão disponíveis acima.
How to do this in code
Lendo e escrevendo NDJSON em código.
py Python
A list comprehension segura tudo em memória. Itere o arquivo direto para processar em fluxo.
import json
# Read
with open('events.ndjson') as f:
records = [json.loads(line) for line in f if line.strip()]
# Write
with open('events.ndjson', 'w') as f:
for r in records:
f.write(json.dumps(r) + '\n')
# pandas knows the format
import pandas as pd
df = pd.read_json('events.ndjson', lines=True) sh jq
-s recolhe todas as entradas em um array; -c escreve um valor compacto por linha. Essas duas flags são a conversão inteira.
# NDJSON to an array
jq -s . events.ndjson > events.json
# An array to NDJSON
jq -c '.[]' events.json > events.ndjson
# Filter a huge NDJSON file without loading it all
jq -c 'select(.level == "error")' events.ndjson js Node
crlfDelay: Infinity faz o readline tratar CRLF como uma única quebra, o que importa em arquivos escritos no Windows.
import { createReadStream } from 'node:fs';
import { createInterface } from 'node:readline';
const rl = createInterface({
input: createReadStream('events.ndjson'),
crlfDelay: Infinity,
});
for await (const line of rl) {
if (!line.trim()) continue;
const record = JSON.parse(line);
// one record at a time, constant memory
} Perguntas frequentes
- NDJSON é a mesma coisa que JSON Lines?
- Para todo efeito prático, sim. São duas especificações pequenas que concordam no essencial: um valor JSON por linha, UTF-8, separados por quebra de linha. As extensões .jsonl e .ndjson são usadas de forma intercambiável.
- Um registro pode ocupar várias linhas?
- Não. Esse é justamente o ponto do formato: a quebra de linha é o separador de registros, então cada registro precisa caber em exatamente uma linha. Minifique cada registro antes de escrever.
- Por que o meu arquivo NDJSON não faz parsing como JSON?
- Porque ele não é um documento JSON, são muitos. O JavaScript reporta "Unexpected non-whitespace character after JSON" e o Python reporta "Extra data". Os dois querem dizer que o parser terminou um valor e encontrou outro.