1. Pendahuluan
Sebagai developer web, kita sering berhadapan dengan data. Entah itu menampilkan laporan, membuat dashboard interaktif, atau bahkan melakukan eksplorasi data. Secara tradisional, pekerjaan analitik data yang berat ini seringkali harus dilakukan di sisi server. Mengapa? Karena browser, dengan segala keterbatasannya, dianggap tidak cukup kuat untuk memproses dataset besar dengan cepat.
Namun, paradigma ini perlahan mulai berubah. Di era modern web, di mana kinerja dan privasi pengguna menjadi prioritas utama, kebutuhan untuk memproses data langsung di sisi klien menjadi semakin mendesak. Bayangkan jika Anda bisa melakukan query SQL kompleks, agregasi data, atau bahkan join antar dataset besar tanpa harus mengirim data bolak-balik ke server. Ini akan mengurangi latensi, menghemat biaya bandwidth dan infrastruktur, serta meningkatkan privasi pengguna karena data tidak perlu keluar dari perangkat mereka.
Di sinilah DuckDB-Wasm hadir sebagai game-changer. DuckDB-Wasm adalah implementasi DuckDB, sebuah database analitik in-process berkinerja tinggi, yang dikompilasi ke WebAssembly (Wasm). Artinya, Anda bisa menjalankan database SQL analitik yang powerful ini langsung di dalam browser atau Web Worker Anda!
Artikel ini akan membawa Anda menyelami DuckDB-Wasm: apa itu, mengapa kita membutuhkannya, bagaimana cara memulainya, memuat berbagai jenis data, melakukan analisis, hingga menyimpan data secara persisten untuk aplikasi offline-first. Siap untuk merevolusi cara Anda berinteraksi dengan data di web? Mari kita mulai!
2. Apa Itu DuckDB-Wasm? Mengapa Kita Membutuhkannya?
Sebelum membahas DuckDB-Wasm, mari kita kenali dulu DuckDB. DuckDB adalah sistem manajemen database relasional (RDBMS) OLAP (Online Analytical Processing) yang dirancang khusus untuk analitik. Berbeda dengan database OLTP (Online Transactional Processing) seperti PostgreSQL atau MySQL yang dioptimalkan untuk transaksi cepat, DuckDB dioptimalkan untuk query analitik yang kompleks pada volume data besar. Keunggulan utamanya adalah:
- In-process: Berjalan di dalam aplikasi Anda, bukan sebagai server terpisah. Ini menghilangkan overhead jaringan.
- Kolumnar: Menyimpan data dalam format kolom, yang sangat efisien untuk query analitik karena hanya kolom yang dibutuhkan yang dibaca.
- Vectorized Execution: Memproses data dalam blok (vektor) besar, memanfaatkan arsitektur CPU modern untuk kecepatan luar biasa.
Nah, DuckDB-Wasm adalah hasil porting DuckDB ke WebAssembly. WebAssembly adalah format instruksi biner tingkat rendah yang dapat dieksekusi oleh browser web dengan kecepatan mendekati native. Dengan WebAssembly, DuckDB dapat berjalan secara efisien di lingkungan browser, membuka potensi luar biasa untuk pemrosesan data sisi klien.
Mengapa Developer Web Membutuhkan DuckDB-Wasm?
📌 Keunggulan DuckDB-Wasm:
- Performa Tinggi: Berkat arsitektur kolumnar dan vectorized execution dari DuckDB, serta kecepatan eksekusi WebAssembly, DuckDB-Wasm dapat memproses jutaan baris data dalam hitungan milidetik langsung di browser. Ini jauh lebih cepat daripada memparsing JSON di JavaScript biasa.
- Zero-Latency Data Fetching: Data yang dianalisis sudah ada di browser, sehingga tidak ada latensi jaringan yang menghambat query.
- Privasi Terjaga: Data sensitif tidak perlu dikirim ke server untuk dianalisis, menjadikannya pilihan ideal untuk aplikasi yang mengutamakan privasi.
- Hemat Biaya Infrastruktur: Mengurangi beban pada server backend Anda, karena banyak pekerjaan analitik bisa di-offload ke klien. Ini berarti biaya server yang lebih rendah.
- Fleksibilitas Data Input: DuckDB sangat pandai membaca berbagai format data langsung, seperti CSV, Parquet, JSON, bahkan dari URL atau
Fileobjek di browser. - Ekosistem SQL yang Familiar: Anda bisa menggunakan sintaks SQL standar yang sudah Anda kenal untuk melakukan analisis.
- Aplikasi Offline-First: Dengan dukungan untuk penyimpanan persisten (menggunakan Origin Private File System/OPFS), Anda bisa membangun aplikasi analitik yang berfungsi penuh bahkan saat offline.
🎯 Contoh Kasus Penggunaan:
- Dashboard Interaktif: Membuat dashboard dengan visualisasi data yang bisa di-drill down atau di-filter secara instan oleh pengguna.
- Aplikasi Data Science Ringan: Melakukan eksplorasi data awal, pembersihan data, atau bahkan melatih model ML sederhana di browser.
- ETL (Extract, Transform, Load) Lokal: Mengubah format data atau menggabungkan dataset dari berbagai sumber sebelum diunggah ke server.
- Aplikasi Pelaporan Kustom: Memungkinkan pengguna membuat laporan ad-hoc dengan query SQL mereka sendiri tanpa membebani backend.
3. Memulai dengan DuckDB-Wasm: Hello World Analitik!
Memulai DuckDB-Wasm sangatlah mudah. Anda bisa mengintegrasikannya ke proyek frontend berbasis JavaScript/TypeScript (React, Vue, Angular, Svelte, atau Vanilla JS).
Instalasi
Pertama, instal paket @duckdb/duckdb-wasm menggunakan npm atau yarn:
npm install @duckdb/duckdb-wasm
# atau
yarn add @duckdb/duckdb-wasm
Inisialisasi dan Query Pertama Anda
DuckDB-Wasm berjalan di dalam Web Worker untuk menjaga main thread tetap responsif. Proses inisialisasi melibatkan pembuatan worker dan instantiate database.
import * as duckdb from '@duckdb/duckdb-wasm';
async function initDuckDB() {
// 1. Dapatkan bundel DuckDB-Wasm dari CDN
// JSDELIVR_BUNDLES menyimpan URL ke file-file Wasm dan Worker.
const JSDELIVR_BUNDLES = duckdb.getBundles();
// 2. Buat Web Worker baru untuk DuckDB.
// Ini akan menjalankan DuckDB di thread terpisah.
const worker = new Worker(JSDELIVR_BUNDLES.mvp.worker);
// 3. Buat logger (opsional, untuk melihat log dari DuckDB)
const logger = new duckdb.ConsoleLogger();
// 4. Inisialisasi AsyncDuckDB.
// AsyncDuckDB adalah wrapper asinkron untuk DuckDB.
const db = new duckdb.AsyncDuckDB(logger, worker);
// 5. Instantiate DuckDB di dalam worker.
// Ini memuat file Wasm utama dan pthread worker (untuk multithreading).
await db.instantiate(JSDELIVR_BUNDLES.mvp.mainModule, JSDELIVR_BUNDLES.mvp.pthreadWorker);
// 6. Buat koneksi ke database.
const conn = await db.connect();
// 7. Jalankan query SQL pertama Anda!
const result = await conn.query("SELECT 'Hello, DuckDB-Wasm!' as message;");
// 8. Tampilkan hasilnya.
// Hasil query biasanya berbentuk Arrow Table, kita konversi ke Array untuk mudah dibaca.
console.log('Hasil query:', result.toArray()); // Output: [{ message: 'Hello, DuckDB-Wasm!' }]
// 9. Tutup koneksi dan terminate database (penting untuk membebaskan sumber daya)
await conn.close();
await db.terminate();
console.log('DuckDB-Wasm berhasil diinisialisasi dan query dieksekusi.');
}
// Panggil fungsi inisialisasi
initDuckDB().catch(console.error);
💡 Tips Praktis:
- Selalu jalankan DuckDB-Wasm di Web Worker (
new Worker(...)) untuk menghindari pemblokiran main thread dan menjaga UI tetap responsif. - Pastikan untuk memanggil
conn.close()dandb.terminate()setelah Anda selesai bekerja dengan database untuk membebaskan sumber daya.
4. Memuat Data: CSV, Parquet, dan Berbagai Sumber Lain
Salah satu kekuatan DuckDB adalah kemampuannya membaca berbagai format data secara langsung. Anda bisa memuat data dari URL, objek File dari input pengguna, atau bahkan buffer data di memori.
Memuat Data dari URL (CSV)
Mari kita coba memuat dataset Iris yang terkenal dari URL publik. DuckDB dapat langsung membaca file CSV dari internet.
import * as duckdb from '@duckdb/duckdb-wasm';
async function loadDataFromURL() {
const JSDELIVR_BUNDLES = duckdb.getBundles();
const worker = new Worker(JSDELIVR_BUNDLES.mvp.worker);
const logger = new duckdb.ConsoleLogger();
const db = new duckdb.AsyncDuckDB(logger, worker);
await db.instantiate(JSDELIVR_BUNDLES.mvp.mainModule, JSDELIVR_BUNDLES.mvp.pthreadWorker);
const conn = await db.connect();
console.log('Memuat dataset Iris dari URL...');
// ✅ DuckDB bisa langsung query CSV dari URL tanpa perlu download manual
await conn.query(`
CREATE TABLE IF NOT EXISTS iris AS SELECT * FROM 'https://raw.githubusercontent.com/plotly/datasets/master/iris.csv';
`);
const count = await conn.query("SELECT COUNT(*) FROM iris;");
console.log('Jumlah baris di iris.csv:', count.toArray()[0]['count_star()']);
const firstFive = await conn.query("SELECT * FROM iris LIMIT 5;");
console.log('5 baris pertama:', firstFive.toArray());
await conn.close();
await db.terminate();
}
loadDataFromURL().catch(console.error);
Memuat Data dari Input Pengguna (File API)
Bagaimana jika pengguna ingin mengunggah file CSV atau Parquet mereka sendiri? DuckDB-Wasm dapat bekerja dengan File objek dari input HTML.
import * as duckdb from '@duckdb/duckdb-wasm';
// Fungsi ini akan dipanggil ketika pengguna memilih file
async function handleFileUpload(file) {
const JSDELIVR_BUNDLES = duckdb.getBundles();
const worker = new Worker(JSDELIVR_BUNDLES.mvp.worker);
const logger = new duckdb.ConsoleLogger();
const db = new duckdb.AsyncDuckDB(logger, worker);
await db.instantiate(JSDELIVR_BUNDLES.mvp.mainModule, JSDELIVR_BUNDLES.mvp.pthreadWorker);
const conn = await db.connect();
try {
// 📌 DuckDB-Wasm bisa mendaftarkan objek File
await db.registerFileHandle(file.name, file);
// Kemudian kita bisa query file tersebut seolah-olah itu adalah tabel
await conn.query(`CREATE TABLE uploaded_data AS SELECT * FROM '${file.name}';`);
const result = await conn.query("SELECT * FROM uploaded_data LIMIT 5;");
console.log(`Data dari ${file.name}:`, result.toArray());
const schema = await conn.query("PRAGMA table_info('uploaded_data');");
console.log('Skema tabel:', schema.toArray());
} catch (error) {
console.error('Gagal memuat atau query file:', error);
} finally {
await conn.close();
await db.terminate();
}
}
// Contoh penggunaan (dalam aplikasi React/Vue/Vanilla JS, ini akan dipicu oleh <input type="file">)
// const inputElement = document.createElement('input');
// inputElement.type = 'file';
// inputElement.onchange = async (e) => {
// const file = e.target.files[0];
// if (file) {
// await handleFileUpload(file);
// }
// };
// document.body.appendChild(inputElement);
// console.log('Silakan unggah file CSV atau Parquet untuk diuji.');
💡 Tips untuk File Parquet:
DuckDB sangat efisien dalam memproses file Parquet karena sifatnya yang kolumnar. Jika Anda memiliki opsi, gunakan Parquet untuk dataset besar. Sintaks query-nya sama: CREATE TABLE my_parquet_data AS SELECT * FROM 'your_file.parquet';
5. Melakukan Analisis Data di Browser
Setelah data dimuat, sekarang saatnya melepaskan kekuatan SQL untuk analisis! Anda bisa melakukan agregasi, filtering, join, dan banyak operasi analitik lainnya, semuanya di sisi klien.
Mari kita gunakan dataset Iris yang sudah kita muat sebelumnya.
import * as duckdb from '@duckdb/duckdb-wasm';
async function analyzeIrisData() {
const JSDELIVR_BUNDLES = duckdb.getBundles();
const worker = new Worker(JSDELIVR_BUNDLES.mvp.worker);
const logger = new duckdb.ConsoleLogger();
const db = new duckdb.AsyncDuckDB(logger, worker);
await db.instantiate(JSDELIVR_BUNDLES.mvp.mainModule, JSDELIVR_BUNDLES.mvp.pthreadWorker);
const conn = await db.connect();
try {
// Pastikan tabel iris sudah ada
await conn.query(`
CREATE TABLE IF NOT EXISTS iris AS SELECT * FROM 'https://raw.githubusercontent.com/plotly/datasets/master/iris.csv';
`);
console.log('Melakukan analisis data Iris...');
// 🎯 Contoh 1: Menghitung rata-rata, min, dan max panjang kelopak untuk setiap spesies
const speciesStats = await conn.query(`
SELECT
"species",
AVG("sepal length") AS avg_sepal_length,
MIN("sepal length") AS min_sepal_length,
MAX("sepal length") AS max_sepal_length,
COUNT(*) AS total_samples
FROM iris
GROUP BY "species"
ORDER BY avg_sepal_length DESC;
`);
console.log('Statistik Sepal Length per Spesies:', speciesStats.toArray());
// 🎯 Contoh 2: Menemukan 10 bunga dengan petal width terbesar
const topPetalWidth = await conn.query(`
SELECT
"sepal length",
"sepal width",
"petal length",
"petal width",
"species"
FROM iris
ORDER BY "petal width" DESC
LIMIT 10;
`);
console.log('10 Bunga dengan Petal Width Terbesar:', topPetalWidth.toArray());
// 🎯 Contoh 3: Membuat tabel baru dengan data yang difilter dan dihitung
await conn.query(`
CREATE TABLE IF NOT EXISTS filtered_iris AS
SELECT
"species",
"sepal length" * "sepal width" AS sepal_area,
"petal length" * "petal width" AS petal_area
FROM iris
WHERE "sepal length" > 5.0 AND "petal length" > 1.5;
`);
const filteredCount = await conn.query("SELECT COUNT(*) FROM filtered_iris;");
console.log('Jumlah baris di filtered_iris:', filteredCount.toArray()[0]['count_star()']);
const filteredSample = await conn.query("SELECT * FROM filtered_iris LIMIT 5;");
console.log('Sampel data filtered_iris:', filteredSample.toArray());
} catch (error) {
console.error('Terjadi kesalahan saat analisis data:', error);
} finally {
await conn.close();
await db.terminate();
}
}
analyzeIrisData().catch(console.error);
Hasil dari query DuckDB-Wasm adalah objek Apache Arrow Table. Ini adalah format data kolumnar yang sangat efisien untuk pertukaran data analitik. Anda bisa mengonversinya ke array objek JavaScript (.toArray()) atau menggunakan metode lain yang disediakan oleh Arrow untuk integrasi lebih lanjut dengan library visualisasi seperti D3.js, Chart.js, atau ECharts.
6. Penyimpanan Data Persisten dan Offline-First
Salah satu fitur paling menarik dari DuckDB-Wasm adalah kemampuannya untuk menyimpan data secara persisten di browser. Ini berarti data Anda tidak akan hilang ketika pengguna menutup tab atau browser, memungkinkan pengalaman offline-first yang sesungguhnya. Fitur ini memanfaatkan Origin Private File System (OPFS), sebuah API baru di browser untuk penyimpanan file berkinerja tinggi.
Untuk menggunakan persistensi, Anda hanya perlu memberikan nama database saat menginisialisasi AsyncDuckDB.
import * as duckdb from '@duckdb/duckdb-wasm';
async function