Topik ini membahas pemetaan skema basis data relasional ke dalam graf Neo4j dengan fokus pada aturan intinya, yaitu foreign key (kunci penunjuk antartabel) menjadi relasi. Contoh yang digunakan adalah empat tabel kecil, yaitu pelanggan, itemtoko, pesanan, dan tabel jembatan pesanan_item yang menghubungkan pesanan dengan barang. Resep impornya terdiri atas dua tahap, yakni impor node per tabel lebih dahulu, kemudian impor relasi dengan MATCH pada kedua ujungnya. Seluruh tahap dijalankan dengan LOAD CSV pada server Neo4j 2026.10, sehingga setiap kueri dapat direproduksi apa adanya. Setelah topik ini dibaca, hasil yang diperoleh adalah graf berisi label :Pelanggan, :Pesanan, dan :ItemToko yang terhubung melalui relasi :MEMESAN serta :MEMUAT.
Pemetaan dari relasional ke graf#
Kesepadanan antara tabel relasional dan struktur graf mengikuti aturan pemetaan yang tetap. Setiap baris pada tabel entitas menjadi satu node, nama tabel menjadi label node, dan setiap kolom menjadi properti node dengan nilai barisnya. Foreign key, yaitu kolom yang menyimpan kunci baris pada tabel lain, diganti menjadi relasi dengan tipe yang diberi nama. Kolom foreign key itu sendiri tidak dipertahankan sebagai properti karena relasinya sudah menyimpan keterhubungan tersebut. Tabel jembatan (junction table) yang memuat hubungan many-to-many menjadi relasi, sedangkan kolom tambahannya, misalnya jumlah, menjadi properti pada relasi itu.
Skema contoh menggunakan tabel pelanggan dengan kolom id dan nama, tabel itemtoko dengan kolom yang sama, serta tabel pesanan yang memuat kolom nomor dan kolom foreign key pelangganId. Keterhubungan pesanan dengan barang dicatat pada tabel jembatan pesanan_item yang berisi kolom nomorPesanan, itemId, dan jumlah. Tabel berikut merangkum pemetaan lengkapnya.
| Elemen relasional | Padanan pada graf | Contoh pada dataset |
|---|---|---|
Tabel pelanggan | label :Pelanggan | tiga baris menjadi tiga node |
Tabel itemtoko | label :ItemToko | tiga baris menjadi tiga node |
Tabel pesanan | label :Pesanan | empat baris menjadi empat node |
Kolom nama | properti nama | nilai barisnya menjadi nilai properti |
Foreign key pelangganId | relasi :MEMESAN | Pesanan → Pelanggan |
Tabel jembatan pesanan_item | relasi :MEMUAT berproperti | kolom jumlah menjadi properti relasi |
Dataset contoh dan penempatan berkas CSV#
Empat berkas CSV berikut mewakili empat tabel tersebut, dengan baris header dan datanya dalam bentuk yang sama persis dengan hasil ekspor dari basis data relasional. Tidak ada pengolahan yang dilakukan pada berkasnya, karena seluruh konversi tipe dan pembentukan relasi dikerjakan oleh kueri Cypher pada tahap impor. Keempatnya tersimpan di samping index.md sebagai aset topik ini.
Perhatian khusus diberikan pada berkas pesanan_item.csv. Tabel jembatan tidak memiliki kunci miliknya sendiri, karena makna setiap barisnya terletak pada pasangan kolom nomorPesanan dan itemId, sedangkan kolom jumlah menjadi keterangan pada pasangan tersebut. Struktur semacam ini justru yang dikehendaki pada graf, yaitu pasangan kunci yang kelak menjadi relasi dan kolom tambahan yang kelak menjadi properti relasinya.
id,nama
1,Sanggar Cempaka
2,Koperasi Pena
3,Studio Anginid,nama
1,Buku Ajar Graf
2,Kalender Meja
3,Kertas Gambar A3nomor,pelangganId
1001,1
1002,1
1003,2
1004,3nomorPesanan,itemId,jumlah
1001,1,2
1001,3,1
1002,2,3
1003,1,1
1003,3,2
1004,2,1Sebelum kueri LOAD CSV dijalankan, keempat berkas disalin ke folder import milik NEO4J_HOME karena jalur file:/// hanya menjangkau folder itu. Penyalinan cukup dilakukan satu kali, dan salinan tersebut berdiri sendiri tanpa mengubah berkas aslinya.
# tidak-dijalankan
# salin keempat berkas CSV ke folder import milik NEO4J_HOME
cp pelanggan.csv itemtoko.csv pesanan.csv pesanan_item.csv "$NEO4J_HOME"/import/Tahap satu: impor node per tabel#
Tahap pertama membawa setiap baris tabel menjadi node, satu kueri per tabel, dan belum ada relasi yang dibuat pada tahap ini. Klausa LOAD CSV WITH HEADERS membaca berkas per baris dengan nama kolom dari header, sedangkan MERGE mengunci setiap node pada kunci bisnisnya agar kueri aman dijalankan ulang tanpa menimbulkan duplikat. Fungsi toInteger wajib ada karena LOAD CSV selalu menghasilkan string, sedangkan kunci id dan nomor berupa bilangan bulat pada skema aslinya. Nama variabel baris pada kueri bersifat bebas dan hanya menjadi pengikat nilai satu baris CSV. Kueri berikut mengimpor tabel pelanggan dan menampilkan hasilnya.
LOAD CSV WITH HEADERS FROM 'file:///pelanggan.csv' AS baris
MERGE (p:Pelanggan {id: toInteger(baris.id)})
SET p.nama = baris.nama;
MATCH (p:Pelanggan)
RETURN p.id AS id, p.nama AS nama
ORDER BY id;id, nama
1, "Sanggar Cempaka"
2, "Koperasi Pena"
3, "Studio Angin"Kueri yang sama berlaku untuk tabel itemtoko, dengan perbedaan hanya pada label dan nama berkasnya.
LOAD CSV WITH HEADERS FROM 'file:///itemtoko.csv' AS baris
MERGE (i:ItemToko {id: toInteger(baris.id)})
SET i.nama = baris.nama;
MATCH (i:ItemToko)
RETURN i.id AS id, i.nama AS nama
ORDER BY id;id, nama
1, "Buku Ajar Graf"
2, "Kalender Meja"
3, "Kertas Gambar A3"Tabel pesanan diimpor dengan pola yang serupa, tetapi kolom foreign key pelangganId ikut disimpan sebagai properti perantara. Properti tersebut belum menjadi relasi, sehingga keluarannya masih menampilkan angka referensi, bukan nama pelanggan.
LOAD CSV WITH HEADERS FROM 'file:///pesanan.csv' AS baris
MERGE (ps:Pesanan {nomor: toInteger(baris.nomor)})
SET ps.pelangganId = toInteger(baris.pelangganId);
MATCH (ps:Pesanan)
RETURN ps.nomor AS nomor, ps.pelangganId AS pelangganId
ORDER BY nomor;nomor, pelangganId
1001, 1
1002, 1
1003, 2
1004, 3Tahap dua: impor relasi dengan MATCH#
Tahap kedua mengubah kolom foreign key menjadi relasi. Resepnya selalu sama, yaitu mengikat kedua node ujung dengan MATCH, kemudian menuliskan pola relasinya pada MERGE. Pola relasi tidak pernah ditulis dengan node ujung yang belum terikat karena MERGE akan membuat node anonim baru untuk setiap baris. Kueri berikut menghubungkan setiap node :Pesanan dengan node :Pelanggan yang direferensikan oleh pelangganId.
MATCH (ps:Pesanan), (p:Pelanggan {id: ps.pelangganId})
MERGE (ps)-[:MEMESAN]->(p);
MATCH (ps:Pesanan)-[:MEMESAN]->(p:Pelanggan)
RETURN ps.nomor AS nomor, p.nama AS pelanggan
ORDER BY nomor;nomor, pelanggan
1001, "Sanggar Cempaka"
1002, "Sanggar Cempaka"
1003, "Koperasi Pena"
1004, "Studio Angin"Keluaran menampilkan nama pelanggan, bukan angka referensi, karena keterhubungan kini tersimpan sebagai relasi. Tabel jembatan pesanan_item diperlakukan dengan resep yang sama, dengan tambahan satu langkah, yaitu kolom jumlah yang menjadi properti pada relasi :MEMUAT.
LOAD CSV WITH HEADERS FROM 'file:///pesanan_item.csv' AS baris
MATCH (ps:Pesanan {nomor: toInteger(baris.nomorPesanan)})
MATCH (i:ItemToko {id: toInteger(baris.itemId)})
MERGE (ps)-[m:MEMUAT]->(i)
SET m.jumlah = toInteger(baris.jumlah);
MATCH (ps:Pesanan)-[m:MEMUAT]->(i:ItemToko)
RETURN ps.nomor AS nomor, i.nama AS item, m.jumlah AS jumlah
ORDER BY nomor, item;nomor, item, jumlah
1001, "Buku Ajar Graf", 2
1001, "Kertas Gambar A3", 1
1002, "Kalender Meja", 3
1003, "Buku Ajar Graf", 1
1003, "Kertas Gambar A3", 2
1004, "Kalender Meja", 1Setelah kedua tahap selesai, properti perantara pelangganId sudah kehilangan fungsinya dan dilepas dengan REMOVE agar tidak ada dua sumber kebenaran untuk satu keterhubungan.
MATCH (ps:Pesanan)
REMOVE ps.pelangganId;
MATCH (ps:Pesanan)
RETURN ps.nomor AS nomor, ps.pelangganId AS pelangganId
ORDER BY nomor;nomor, pelangganId
1001, NULL
1002, NULL
1003, NULL
1004, NULLMemeriksa hasil pemetaan#
Graf hasil impor diperiksa dari dua sisi, yaitu jumlah objeknya dan jalur yang tersimpan. Jumlah node pada dataset ini adalah tiga node :Pelanggan, empat node :Pesanan, dan tiga node :ItemToko, sedangkan jumlah relasinya empat relasi :MEMESAN dan enam relasi :MEMUAT. Angka relasi :MEMUAT sama dengan banyaknya baris pada tabel jembatan, karena setiap baris jembatan menjadi satu relasi. Pemeriksaan jumlah layak dilakukan karena mesin tidak melaporkan baris yang dilewati, sehingga kekurangan relasi tidak pernah muncul sebagai error. Kueri berikut menelusuri jalur lengkap dari pelanggan hingga barang yang dimuat pesanannya, sehingga seluruh pemetaan terlihat dalam satu keluaran.
MATCH (p:Pelanggan)<-[:MEMESAN]-(ps:Pesanan)-[m:MEMUAT]->(i:ItemToko)
RETURN p.nama AS pelanggan, ps.nomor AS nomor, i.nama AS item, m.jumlah AS jumlah
ORDER BY nomor, item;pelanggan, nomor, item, jumlah
"Sanggar Cempaka", 1001, "Buku Ajar Graf", 2
"Sanggar Cempaka", 1001, "Kertas Gambar A3", 1
"Sanggar Cempaka", 1002, "Kalender Meja", 3
"Koperasi Pena", 1003, "Buku Ajar Graf", 1
"Koperasi Pena", 1003, "Kertas Gambar A3", 2
"Studio Angin", 1004, "Kalender Meja", 1Setiap baris keluaran memuat nama pelanggan, nomor pesanan, nama barang, dan jumlahnya dalam satu jalur tersimpan. Ketika salah satu tahap impor terlewat, baris yang bersangkutan hilang dari keluaran ini, sehingga penelusuran jalur sekaligus menjadi pemeriksaan kelengkapan yang mudah. Pertanyaan keterhubungan semacam ini dijawab graf dengan penelusuran relasi, tanpa JOIN yang dihitung saat kueri berjalan, karena relasi antarentitas sudah berbentuk data.
Kesalahan umum#
Tiga kesalahan berikut paling sering muncul saat resep ini dipraktikkan.
- Impor relasi dijalankan sebelum node ujungnya ada.
MATCHtidak menemukan pasangan, kueri tetap berjalan sukses tanpa membuat apa pun, dan kekurangan relasi baru terlihat jauh setelahnya. Perbaikannya adalah memastikan seluruh kueri tahap satu sudah dijalankan dan jumlah node setiap label sudah sesuai sebelum tahap dua dimulai. - Nilai kunci tidak dikonversi dengan
toInteger. Pola{id: baris.id}mencocokkan string"1"dengan bilangan1yang tersimpan, dan kedua nilai itu tidak pernah sama, sehingga relasi tidak terbentuk untuk baris mana pun. Perbaikannya adalah membungkus setiap kolom kunci dengantoInteger, sebagaimana seluruh contoh pada topik ini. - Properti foreign key dipertahankan setelah relasinya terbentuk. Graf menyimpan keterhubungan yang sama pada dua tempat, dan keduanya dapat berbeda isi ketika data diperbarui. Perbaikannya adalah melepas properti perantara dengan
REMOVEsetelah relasi terverifikasi.
Ringkasan#
- Setiap baris tabel menjadi node dengan label dari nama tabelnya, sedangkan kolomnya menjadi properti node.
- Foreign key menjadi tipe relasi, dan tabel jembatan many-to-many menjadi relasi berproperti.
- Resep impornya dua tahap, yaitu impor node per tabel dengan
MERGEberkunci, kemudian impor relasi dengan mengikat kedua ujungnya melaluiMATCH. - Kolom foreign key dilepas dengan
REMOVEsetelah relasi penggantinya terbentuk agar keterhubungan tidak tersimpan dua kali.
Referensi#
- LOAD CSV — Neo4j Docs
— Referensi klausa
LOAD CSVbeserta opsi header, pemisah, dan penanganan nilai string. - Import from a relational database into Neo4j — Neo4j Docs
— Ikhtisar metode impor dari basis data relasional, termasuk jalur ekspor CSV dengan
LOAD CSV. - Modeling: relational to graph — Neo4j Docs — Kiat transformasi model data, antara lain baris menjadi node, foreign key menjadi relasi, dan tabel join menjadi relasi berproperti.