NDJSON in JSON
Trasforma record separati da a capo in un unico array, e segnala la riga che fallisce.
Nulla di ciò che incolli lascia il tuo browser. L’allowlist connect-src ne fa una garanzia del browser anziché una promessa. Verificalo tu stesso
Trasforma JSON delimitato da a capo in un unico array. Ogni riga viene analizzata in modo indipendente, e qualsiasi riga che fallisce viene segnalata con il suo numero invece di far cadere l’intero file.
NDJSON è ciò che esce da pipeline di log, esportazioni BigQuery, file bulk di Elasticsearch e API in streaming, ed è ciò che provoca gli errori «Extra data» e «unexpected non-whitespace character» quando lo si analizza come un unico documento.
Che cos’è NDJSON
Un valore JSON completo per riga, separati da un a capo. Nessuna virgola tra i record, nessun array che li racchiude. Le righe vuote vengono ignorate. Le estensioni convenzionali sono .ndjson e .jsonl.
JSON Lines e NDJSON sono di fatto lo stesso formato descritto da due piccole specifiche che concordano su tutto ciò che conta. Alcuni strumenti nominano l’uno e altri l’altro; un file scritto per uno viene letto correttamente da entrambi.
Perché esiste
Tre vantaggi concreti, tutti derivanti dal fatto che i record sono indipendenti.
- Si può trasmettere in streaming
- Chi lo consuma elabora un record alla volta e non tiene mai in mano l’intero file. Un export da 50 GB va bene; un array JSON da 50 GB no.
- Si può accodare
- Aggiungere un record è una sola scrittura alla fine del file. Accodare a un array JSON significa riscrivere la parentesi di chiusura, e non è affatto un’accodatura.
- Sopravvive alla corruzione
- Una riga malformata ti costa un record. Un byte malformato in un array JSON ti costa il file.
In quale direzione convertire
Verso un array quando i dati vanno dove ci si aspetta un documento unico: un browser, il corpo di una richiesta, un file di configurazione. Verso NDJSON quando finiscono in una pipeline, in un log, in un file append-only o in qualunque cosa faccia streaming. Entrambe le direzioni sono qui sopra.
How to do this in code
Leggere e scrivere NDJSON nel codice.
py Python
La list comprehension tiene tutto in memoria. Itera direttamente sul file per elaborarlo in streaming.
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 raccoglie tutti gli input in un array; -c scrive un valore compatto per riga. Quelle due opzioni sono l’intera conversione.
# 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 fa trattare a readline il CRLF come un solo a capo, cosa che conta per i file scritti su 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
} Domande frequenti
- NDJSON è la stessa cosa di JSON Lines?
- A tutti gli effetti pratici, sì. Sono due piccole specifiche che concordano sulle parti importanti: un valore JSON per riga, UTF-8, separati da a capo. Le estensioni .jsonl e .ndjson si usano in modo intercambiabile.
- Un record può occupare più righe?
- No. È tutto il senso del formato: l’a capo è il separatore dei record, quindi ogni record deve stare su esattamente una riga. Minifica ogni record prima di scriverlo.
- Perché il mio file NDJSON non si analizza come JSON?
- Perché non è un documento JSON, sono molti. JavaScript riporta «Unexpected non-whitespace character after JSON» e Python riporta «Extra data». Entrambi significano che il parser ha finito un valore e ne ha trovato un altro.