Aplikasi kasir mencatat transaksi baru setiap menit, dan file pencatatan terus membesar sepanjang hari. Jika seluruh transaksi disimpan sebagai satu array JSON, dokumen tersebut baru sah setelah kurung siku penutup ditulis — menambah satu transaksi berarti membaca seluruh file, menambah elemen, lalu menulis ulang. JSON Lines (JSONL) menjawab masalah ini dengan satu aturan sederhana: setiap baris berisi tepat satu objek JSON yang lengkap dan berdiri sendiri. Format ini menjadi standar de facto untuk log aplikasi, streaming, dan export data bertahap — BigQuery memakainya untuk mengekspor tabel besar — seperti dijelaskan situs resminya di jsonlines.org .
Menulis File .jsonl #
Menulis JSONL tidak membutuhkan library khusus — kita tetap memakai json.dumps(), hanya dengan dua disiplin tambahan: hasil serialisasi harus satu baris (tanpa indent), dan setiap baris diakhiri karakter baris baru. Data transaksi toko dari chapter sebelumnya kita tulis ulang dalam format ini:
import json
transaksi = [
{"id": 1, "kasir": "Budi", "produk": "Kopi Robusta", "qty": 2, "harga": 45000},
{"id": 2, "kasir": "Siti", "produk": "Teh Melati", "qty": 3, "harga": 15000},
{"id": 3, "kasir": "Budi", "produk": "Gula Aren, 500g", "qty": 1, "harga": 25000},
{"id": 4, "kasir": "Dewi", "produk": "Susu UHT 1L", "qty": 2, "harga": 18000},
]
with open("transaksi.jsonl", "w", encoding="utf-8") as berkas:
for t in transaksi:
berkas.write(json.dumps(t, ensure_ascii=False) + "\n")
print(open("transaksi.jsonl", encoding="utf-8").read())Output yang Dihasilkan:
{"id": 1, "kasir": "Budi", "produk": "Kopi Robusta", "qty": 2, "harga": 45000}
{"id": 2, "kasir": "Siti", "produk": "Teh Melati", "qty": 3, "harga": 15000}
{"id": 3, "kasir": "Budi", "produk": "Gula Aren, 500g", "qty": 1, "harga": 25000}
{"id": 4, "kasir": "Dewi", "produk": "Susu UHT 1L", "qty": 2, "harga": 18000}Mari kita telaah baris-baris kode di atas:
- Baris 10-12 (
for t in transaksi: ...): setiap dictionary diserialisasi menjadi satu string JSON padat, lalu ditulis denganwrite()dan ditutup"\n"— satu record, satu baris. - Baris 12 (
json.dumps(t, ensure_ascii=False)): tanpaindenthasilnya pasti satu baris; karakterédan koma di dalam nama produk tetap aman karena JSONL dibaca per baris, bukan per delimiter. - Baris 14 (
print(open(...).read())): menampilkan isi file — empat baris, masing-masing adalah dokumen JSON yang valid jika dites sendiri-sendiri.
Membaca Baris demi Baris #
Iterasi atas objek file di Python membaca isi secara lazy: satu baris diproses pada satu waktu, dan sisa file tidak pernah tersentuh. Perilaku ini membuat JSONL cocok untuk file berukuran besar — proses berhenti kapan pun hasil yang dibutuhkan sudah diperoleh:
import json
with open("transaksi.jsonl", encoding="utf-8") as berkas:
for nomor, baris in enumerate(berkas, start=1):
t = json.loads(baris)
print(f"baris {nomor}: transaksi {t['id']} oleh {t['kasir']}")
if t["id"] == 2:
print("berhenti di sini, sisa file tidak diproses")
break
teks_utuh = open("transaksi.jsonl", encoding="utf-8").read()
try:
json.loads(teks_utuh)
except json.JSONDecodeError as galat:
print("JSONDecodeError:", galat)Output yang Dihasilkan:
baris 1: transaksi 1 oleh Budi
baris 2: transaksi 2 oleh Siti
berhenti di sini, sisa file tidak diproses
JSONDecodeError: Extra data: line 2 column 1 (char 79)Tiga bukti penting ada pada hasil di atas. Pertama, break menghentikan pemrosesan setelah transaksi kedua — baris ketiga dan keempat tidak pernah dibaca. Kedua, json.loads(baris) dipanggil per baris, sehingga kegagalan satu baris tidak menular ke baris lain. Ketiga, percobaan mem-parse seluruh isi file sebagai satu dokumen JSON memicu JSONDecodeError — JSONL memang bukan satu dokumen JSON, melainkan rangkaian dokumen.
Menambah Data dengan Mode Append #
Kekuatan sesungguhnya JSONL muncul saat data bertambah. Mode "a" pada open() menulis langsung di akhir file tanpa membaca isi lama, jadi menambah satu transaksi tidak peduli seberapa besar file pencatatan tersebut:
import json
transaksi_baru = {"id": 5, "kasir": "Siti", "produk": "Café Latte", "qty": 1, "harga": 32000}
with open("transaksi.jsonl", "a", encoding="utf-8") as berkas:
berkas.write(json.dumps(transaksi_baru, ensure_ascii=False) + "\n")
with open("transaksi.jsonl", encoding="utf-8") as berkas:
jumlah = sum(1 for baris in berkas if baris.strip())
print("jumlah baris sekarang:", jumlah)
with open("transaksi.jsonl", encoding="utf-8") as berkas:
for baris in berkas:
t = json.loads(baris)
if t["id"] == 5:
print("transaksi terakhir:", t["produk"], t["harga"])Output yang Dihasilkan:
jumlah baris sekarang: 5
transaksi terakhir: Café Latte 32000Perbandingan lengkap kedua gaya penyimpanan dirangkum berikut:
| Aspek | Array JSON (.json) | JSON Lines (.jsonl) |
|---|---|---|
| Struktur | satu dokumen array utuh | satu objek JSON per baris |
| Menambah data | baca semua, tulis ulang file | tambah satu baris di akhir |
| Proses sebagian data | wajib parse dokumen penuh | berhenti kapan saja per baris |
| Satu baris rusak | seluruh dokumen gagal parse | hanya baris tersebut gagal |
JSONL menuntut satu objek per baris, tetapi banyak sistem lama justru menyimpan dokumen bertingkat dengan atribut dan namespace — dunia XML.