Node antara

Mengubah relasi yang memerlukan fakta sendiri menjadi node tersendiri.

Daftar isi

Node antara (intermediate node) adalah node yang menggantikan sebuah relasi ketika relasi itu mulai memerlukan identitas dan fakta sendiri. Topik ini membahas sinyal yang menandai kebutuhan tersebut, pola entitas hubungan sebagai bentuk perubahannya, serta evolusi ranah piket dari relasi :MELAKSANAKAN menjadi node :Penugasan yang terhubung melalui relasi :MENGISI dan :UNTUK. Seluruh kueri dijalankan pada server Neo4j yang sama dengan topik lain pada modul ini, dan setiap keluaran ditampilkan apa adanya. Setelah membacanya, keputusan mengangkat sebuah relasi menjadi node dapat diambil dengan alasan yang jelas, dan kueri agregasi per peristiwa dapat ditulis langsung pada struktur yang baru.

Sinyal relasi membutuhkan identitas#

Model property graph (graf berproperti) menetapkan bahwa setiap relasi menghubungkan tepat dua node, dan relasi tidak dapat menjadi ujung relasi lain. Neo4j tidak menyediakan hipergraf (hyperedge), yaitu relasi yang menjangkau lebih dari dua node sekaligus, sehingga kebutuhan semacam itu harus diselesaikan pada level pemodelan. Batas ini muncul ketika sebuah peristiwa antara dua entitas membutuhkan fakta yang tidak lagi muat sebagai properti, misalnya pemeriksaan atas hasil kerja, catatan dari pihak lain, atau keterlibatan peserta tambahan.

Sinyal utamanya adalah relasi yang membutuhkan relasi sendiri. Pada model piket yang sudah dibangun, peristiwa piket tersimpan sebagai relasi :MELAKSANAKAN dari node :Orang menuju node :Tugas dengan properti tanggal dan status. Pertanyaan baru tentang pemeriksaan hasil piket menuntut sebuah relasi dari pemeriksa menuju peristiwa tersebut, sedangkan peristiwanya berbentuk relasi dan bukan node, sehingga relasi pemeriksa tidak memiliki titik tujuan yang sah. Sinyal kedua adalah satu entitas yang terikat pada banyak peristiwa sejenis dengan keterangan berbeda, sebagaimana Endang yang menjadi pelaksana dua piket dengan tanggal dan statusnya masing-masing.

Ketika salah satu sinyal muncul, properti tambahan bukan lagi jalan keluarnya. Nilai majemuk yang ditumpuk pada satu properti tidak dapat disaring maupun dihitung per elemennya. Solusi yang tepat adalah memberi identitas pada peristiwanya sendiri, dan identitas dalam graf berbentuk node.

Pola entitas hubungan#

Perubahan yang tepat atas kedua sinyal tersebut adalah pola entitas hubungan (relationship entity), yaitu mengangkat relasi menjadi node dan memecahnya menjadi dua relasi penghubung. Satu relasi (:Orang)-[:MELAKSANAKAN]->(:Tugas) menjadi jalur tiga bagian (:Orang)-[:MENGISI]->(:Penugasan)-[:UNTUK]->(:Tugas), dan properti tanggal serta status berpindah dari relasi ke node :Penugasan. Node baru tersebut memiliki label sendiri, dapat disaring langsung pada pola MATCH, dan dapat menjadi titik awal relasi tambahan tanpa mengubah kedua ujung lamanya.

Diagram berikut menggambar evolusi tersebut dari atas ke bawah, yaitu dari relasi yang membawa properti pada baris atas menjadi node antara dengan propertinya sendiri pada baris bawah.

SebelumOrangTugasMELAKSANAKAN{tanggal, status}relasi diangkat menjadi node antaraSesudahOrangTugasPenugasankode, tanggal, statusMENGISIUNTUK
Evolusi relasi MELAKSANAKAN menjadi node antara Penugasan

Kedua relasi penghubung diberi nama yang melengkapi satu sama lain. MENGISI menyatakan hubungan pelaksana dengan peristiwanya, sedangkan UNTUK menyatakan sasaran peristiwa tersebut. Arah keduanya membentuk satu garis baca dari orang menuju tugas, sehingga pola MATCH tiga bagian tetap terbaca sebagai satu kalimat yang runtut. Pemecahan ini juga membuat setiap peristiwa berdiri sebagai satu node tersendiri, sehingga dua peristiwa pada tanggal yang sama tidak saling menimpa.

Evolusi ranah piket#

Skrip berikut menerapkan pola tersebut atas lima peristiwa piket yang sudah tersimpan pada graf. Setiap pernyataan mengikat kedua ujungnya dengan MATCH, membuat node :Penugasan dengan MERGE, mengisi properti milik peristiwanya, lalu menghubungkan node itu melalui MENGISI dan UNTUK. Pernyataan yang sama aman dijalankan berulang karena MERGE mencari node dengan kode yang sama terlebih dahulu, sehingga tidak ada peristiwa ganda yang tercipta.

cypher
MATCH (o:Orang {nama: "Doni"}), (t:Tugas {nama: "Menyapu lantai"})
MERGE (p:Penugasan {kode: "piket-2026-11-02-doni"})
  SET p.tanggal = date("2026-11-02"), p.status = "selesai"
MERGE (o)-[:MENGISI]->(p)-[:UNTUK]->(t);
MATCH (o:Orang {nama: "Endang"}), (t:Tugas {nama: "Menyapu lantai"})
MERGE (p:Penugasan {kode: "piket-2026-11-03-endang"})
  SET p.tanggal = date("2026-11-03"), p.status = "selesai"
MERGE (o)-[:MENGISI]->(p)-[:UNTUK]->(t);
MATCH (o:Orang {nama: "Doni"}), (t:Tugas {nama: "Merapikan perpustakaan"})
MERGE (p:Penugasan {kode: "piket-2026-11-04-doni"})
  SET p.tanggal = date("2026-11-04"), p.status = "selesai"
MERGE (o)-[:MENGISI]->(p)-[:UNTUK]->(t);
MATCH (o:Orang {nama: "Fita"}), (t:Tugas {nama: "Merapikan perpustakaan"})
MERGE (p:Penugasan {kode: "piket-2026-11-04-fita"})
  SET p.tanggal = date("2026-11-04"), p.status = "selesai"
MERGE (o)-[:MENGISI]->(p)-[:UNTUK]->(t);
MATCH (o:Orang {nama: "Endang"}), (t:Tugas {nama: "Menyiram tanaman"})
MERGE (p:Penugasan {kode: "piket-2026-11-05-endang"})
  SET p.tanggal = date("2026-11-05"), p.status = "tertunda"
MERGE (o)-[:MENGISI]->(p)-[:UNTUK]->(t);
MATCH (o:Orang)-[:MENGISI]->(p:Penugasan)-[:UNTUK]->(t:Tugas)
RETURN DISTINCT o.nama AS orang, p.kode AS kode, p.tanggal AS tanggal, p.status AS status, t.nama AS tugas
ORDER BY p.tanggal, orang;
text Keluaran
orang, kode, tanggal, status, tugas
"Doni", "piket-2026-11-02-doni", 2026-11-02, "selesai", "Menyapu lantai"
"Endang", "piket-2026-11-03-endang", 2026-11-03, "selesai", "Menyapu lantai"
"Doni", "piket-2026-11-04-doni", 2026-11-04, "selesai", "Merapikan perpustakaan"
"Fita", "piket-2026-11-04-fita", 2026-11-04, "selesai", "Merapikan perpustakaan"
"Endang", "piket-2026-11-05-endang", 2026-11-05, "tertunda", "Menyiram tanaman"

Nilai kode seperti piket-2026-11-04-doni menyimpan tanggal sekaligus nama pelaksananya karena dua peristiwa jatuh pada tanggal 4 November 2026, sehingga tanggal saja tidak cukup menjadi identitas. Keluaran menampilkan lima peristiwa lengkap dengan pelaksana, tanggal, status, dan sasarannya, dan seluruhnya terbaca melalui satu pola MATCH tiga bagian.

Relasi :MELAKSANAKAN lama tetap tersimpan pada graf bersama modul ini agar kedua bentuk model dapat dibandingkan berdampingan, sedangkan seluruh kueri berikut hanya menunjuk jaringan :Penugasan. Pada basis data milik sendiri, relasi lama dihapus setelah perpindahan selesai agar tidak ada dua salinan fakta yang hidup berdampingan.

Fakta tambahan menemukan tempatnya#

Pertanyaan yang mendorong evolusi ini kini memiliki tempat jawabannya. Misalnya, Fita memeriksa hasil piket Doni pada tanggal 2 November 2026 dan mencatat hasil pemeriksaannya. Fakta pemeriksaan itu milik peristiwa, dan peristiwanya kini berupa node :Penugasan, sehingga relasi :MEMERIKSA dari Fita menuju peristiwa tersebut memiliki titik tujuan yang sah. Kueri berikut mencatat pemeriksaan itu beserta keterangannya pada properti relasi.

cypher
MATCH (p:Penugasan {kode: "piket-2026-11-02-doni"}), (c:Orang {nama: "Fita"})
MERGE (c)-[m:MEMERIKSA]->(p)
SET m.catatan = "lantai sudah bersih";
MATCH (c:Orang)-[m:MEMERIKSA]->(p:Penugasan)-[:UNTUK]->(t:Tugas)
RETURN DISTINCT p.kode AS kode, c.nama AS pemeriksa, m.catatan AS catatan, t.nama AS tugas
ORDER BY kode;
text Keluaran
kode, pemeriksa, catatan, tugas
"piket-2026-11-02-doni", "Fita", "lantai sudah bersih", "Menyapu lantai"

Pada model relasi, fakta yang sama tidak memiliki tempat yang tepat. Properti catatanPemeriksa pada relasi :MELAKSANAKAN memang dapat menampung teksnya, tetapi pemeriksa hanya tersimpan sebagai bagian dari string sehingga tidak dapat disaring, dihitung, maupun dihubungkan ke entitas lain. Dengan node antara, pemeriksa tetap berupa node :Orang yang tersambung penuh ke graf, dan pemeriksaan lain atas peristiwa yang sama cukup ditambahkan sebagai relasi baru.

Agregasi per peristiwa#

Node :Penugasan menjadikan peristiwa sebagai satuan hitung yang langsung tersedia bagi kueri. Penghitungan per tanggal, per pelaksana, per tugas, dan per status semuanya berangkat dari node yang sama, sehingga tidak ada perbandingan properti antara relasi yang perlu ditulis secara manual. Fungsi count(p) menghitung node peristiwa, sedangkan kunci pengelompokannya berupa properti yang dituliskan pada RETURN. Kueri berikut menghitung jumlah peristiwa untuk setiap tanggal.

cypher
MATCH (p:Penugasan)
RETURN p.tanggal AS tanggal, count(p) AS jumlah
ORDER BY tanggal;
text Keluaran
tanggal, jumlah
2026-11-02, 1
2026-11-03, 1
2026-11-04, 2
2026-11-05, 1

Keluaran menampilkan angka dua pada tanggal 4 November 2026 karena Doni dan Fita masing-masing memiliki peristiwa tersendiri yang tidak saling menimpa. Penghitungan per pelaksana menjangkau node :Orang melalui relasi MENGISI, sedangkan penghitungan per status cukup membaca node :Penugasan secara langsung. Pola yang sama melayani pertanyaan lain melalui penggantian kunci pengelompokan saja, misalnya p.status untuk status atau t.nama untuk tugasnya, tanpa perubahan model apa pun. Seluruh dimensi tersebut bertemu pada satu titik karena setiap peristiwa kini menjadi titik temu bagi pelaksana, sasaran, dan fakta tambahannya.

Kesalahan umum#

Tiga kesalahan berikut paling sering muncul ketika pola ini dipraktikkan.

  1. Relasi penghubung yang setengah jalan. Node :Penugasan yang hanya menerima relasi MENGISI tanpa UNTUK membuat pola tiga bagian tidak pernah cocok, sehingga kueri mengembalikan nol baris tanpa pesan error apa pun. Perbaikannya adalah menuliskan kedua relasi penghubung dalam satu pernyataan MERGE sebagaimana skrip evolusi di atas.
  2. Dua salinan fakta yang hidup bersamaan. Menambahkan node antara sambil membiarkan tanggal dan status tetap pada relasi lama menciptakan dua sumber kebenaran yang saling bertentangan begitu salah satunya diperbarui. Satu fakta hanya boleh tersimpan pada satu tempat, sehingga salinan pada relasi lama dihapus setelah perpindahannya selesai.
  3. Mengangkat setiap relasi menjadi node antara. Satu node antara menambah satu node dan dua relasi untuk setiap peristiwa, sehingga graf membesar dengan cepat tanpa manfaat kueri. Relasi yang tidak pernah membutuhkan identitas maupun relasi sendiri lebih tepat tetap berbentuk relasi dengan propertinya.

Ringkasan#

  • Relasi tidak dapat menjadi ujung relasi lain, sehingga peristiwa yang mulai membutuhkan fakta sendiri ditandai untuk diangkat menjadi node antara.
  • Pola entitas hubungan memecah satu relasi menjadi dua relasi penghubung dengan node peristiwa di tengahnya, dan properti peristiwa berpindah ke node tersebut.
  • Identitas node antara ditetapkan melalui properti kode yang unik bagi setiap peristiwa, karena tanggal saja dapat meleburkan dua peristiwa pada hari yang sama.
  • Dengan node antara, fakta tambahan seperti pemeriksaan memperoleh titik tujuan yang sah, dan peristiwa menjadi satuan hitung bagi agregasi.

Referensi#