Menengah7 menit baca

Relasi One-to-Many di DynamoDB

Control plane SaaS hampir selalu punya hierarki berbasis kepemilikan: satu workspace memiliki banyak proyek. Di SQL Anda akan menaruh foreign key workspace_id di tabel proyek lalu melakukan JOIN.

DynamoDB tidak punya join dan tidak punya foreign key, jadi relasinya harus hidup di dalam key schema itu sendiri. Dilakukan dengan benar, "muat sebuah workspace dan setiap proyek di dalamnya" menjadi satu Query saja, bukan satu pembacaan plus scan lanjutan.

Bagaimana cara memodelkan relasi one-to-many di DynamoDB?

Berikan induk dan semua anaknya yang sama agar mereka berbagi satu , lalu bedakan mereka dengan sort key. DynamoDB tidak punya join atau foreign key, jadi relasinya hidup di dalam key schema itu sendiri. Memuat sebuah induk plus setiap anaknya kemudian menjadi satu Query saja, bukan sebuah join.

  • Modelkan pembacaannya, bukan entitasnya. Relasi one-to-many hanya ada untuk melayani "daftarkan proyek-proyek sebuah workspace" — bentuk key-nya di sekitar query itu.
  • Encode induk ke dalam anaknya. Berikan workspace dan semua proyeknya nilai partition-key yang sama agar mereka jatuh di satu .
  • Lalu pembacaan daftar itu adalah satu Query. Induk plus anak-anaknya kembali bersama-sama — tanpa join, tanpa round trip kedua (sebuah Query mengembalikan hingga 1 MB per halaman, memaginasi lewat LastEvaluatedKey di luar itu).
  • Waspadai . Satu tenant raksasa memusatkan semua trafiknya di satu partisi; sebuah workspace besar mungkin butuh key ter-shard dan pembacaan fan-out.

Pola akses, lebih dulu

Pemodelan DynamoDB adalah access-pattern-first, bukan entity-first — disiplin yang sama di balik single-table design. Sebelum memilih key apa pun, tuliskan pembacaan yang benar-benar dikeluarkan aplikasi:

  • Ambil setelan satu workspace.
  • Daftarkan setiap proyek di sebuah workspace, terbaru dulu.
  • Ambil satu proyek spesifik berdasarkan id.

Relasi "satu workspace, banyak proyek" hanya penting karena pembacaan #2. Jika Anda tak pernah perlu mendaftarkan proyek-proyek sebuah workspace bersama-sama, Anda tak akan memodelkan relasinya sama sekali — Anda akan menyimpan proyek secara independen.

Jadi pertanyaannya tak pernah "bagaimana saya merepresentasikan one-to-many?" secara abstrak. Melainkan "query mana yang harus dilayani relasi ini?" Jawab itu, lalu bentuk key-nya di sekitarnya.

Kenapa foreign key tak akan membantu di sini

Di DynamoDB setiap GetItem dan Query menargetkan sebuah partition key, dan layanan itu meng-hash key tersebut untuk menemukan partisi yang menampung Item-nya.

AWS menyatakannya langsung di dokumen Core Components: nilai partition-key adalah input untuk fungsi hash internal yang memutuskan di mana data berada.

Penempatan berbasis-hash itu adalah warisan dari makalah Dynamo: Amazon's Highly Available Key-value Store tahun 2007 yang asli, tempat consistent hashing mendistribusikan key ke seluruh node.

Sebuah atribut workspace_id telanjang pada Item proyek tak terlihat oleh mesin itu — DynamoDB tak bisa "mengikutinya".

Untuk mengambil Item terkait dalam satu request, identitas induk harus di-encode ke dalam partition key proyek, sehingga semua Item sebuah workspace ter-hash ke partisi yang sama dan satu Query bisa menyapunya.

Contoh terpandu: workspace dan proyek

Gunakan key schema generik yang di-overload. Sebut partition key EntityRef dan sort key Detail. Identitas workspace masuk ke EntityRef untuk baik Item workspace maupun setiap proyek di bawahnya:

EntityRefDetailattributes
WS#acmeMETAdisplayName, region, seatLimit
WS#acmePROJ#2026-0007title, status, createdBy
WS#acmePROJ#2026-0042title, status, createdBy
WS#acmePROJ#2026-0118title, status, createdBy
WS#globexMETAdisplayName, region, seatLimit
WS#globexPROJ#2026-0009title, status, createdBy

Workspace dan semua proyeknya berbagi EntityRef = "WS#acme", jadi mereka membentuk satu koleksi Item yang hidup bersama di satu partisi.

Sort key Detail memisahkan mereka: META adalah rekaman workspace, dan setiap proyek membawa prefiks PROJ# dengan id yang time-ordered dan zero-padded sehingga proyek terurut secara alami.

Secara visual, induk dan anak-anaknya bertumpuk di dalam satu partisi, terurut berdasarkan sort key:

Partisi: EntityRef = WS#acmeMETA pengaturan workspacePROJ#2026-0007PROJ#2026-0042PROJ#2026-0118

Satu Query pada EntityRef = "WS#acme" menyapu seluruh tumpukan — induk plus setiap anak — dalam satu pembacaan.

Kini ketiga pola akses masing-masing runtuh menjadi satu panggilan:

  • Setelan workspaceGetItem(EntityRef="WS#acme", Detail="META").
  • Daftarkan proyek terbaru-duluQuery(EntityRef="WS#acme") dengan Detail begins_with "PROJ#", dijalankan dalam urutan menurun (ScanIndexForward = false).
  • Satu proyekGetItem(EntityRef="WS#acme", Detail="PROJ#2026-0042").

Yang kedua adalah inti keseluruhannya: induk dan anak-anaknya kembali dari satu Query, tanpa join dan tanpa round trip kedua — DynamoDB mengembalikan hingga 1 MB per halaman dan memberi Anda LastEvaluatedKey untuk mengambil sisanya. Itulah gerakan yang tak bisa Anda lakukan dengan atribut foreign-key dan sebuah Scan.

Menulis kondisi begins_with itu dengan tangan merepotkan — sintaks key-condition dan projection-expression menggigit.

DynamoDB Expression Builder menghasilkan KeyConditionExpression, peta placeholder #name/:value, dan cuplikan SDK yang siap jalan agar Anda tak berkelahi dengan tata bahasanya:

KeyConditionExpression     "#er = :er AND begins_with(#d, :p)"
ExpressionAttributeNames   { "#er": "EntityRef", "#d": "Detail" }
ExpressionAttributeValues  { ":er": "WS#acme", ":p": "PROJ#" }

Inspeksi koleksi Item di DynoTable

Hasil tata letak ini bersifat visual: setiap baris yang berbagi sebuah EntityRef adalah workspace plus anak-anaknya, duduk bersebelahan.

DynoTable mengelompokkan mereka sehingga Anda melihat relasi one-to-many sebagai satu blok yang bersambung alih-alih menebak-nebaknya di seberang tabel-tabel terpisah.

Item META workspace dan anak-anak PROJ#-nya dikelompokkan sebagai satu koleksi Item di tampilan tabel DynoTable.
Item META workspace dan anak-anak PROJ#-nya dikelompokkan sebagai satu koleksi Item di tampilan tabel DynoTable.

Jebakan dan bentuk alternatifnya

Beberapa hal yang perlu diwaspadai:

  • Hot partition. Setiap Item untuk satu workspace hidup di satu partisi, jadi satu tenant yang sangat besar atau sangat sibuk memusatkan trafik. Perilaku adaptive capacity yang dijelaskan AWS menyerap kemiringan sedang, tetapi sebuah workspace dengan jutaan proyek mungkin butuh key ter-shard (mis. WS#acme#01 … #10) dan pembacaan fan-out.
  • Ukuran koleksi Item. Dengan sebuah local secondary index, koleksi Item satu partisi dibatasi hingga 10 GB; tanpa LSI tak ada batas seperti itu. Jika Anda sedang menimbang tipe indeks di sini, lihat GSI vs LSI.
  • Raih Query, jangan pernah Scan. Seluruh desain ini ada agar Anda bisa Query satu partisi. Jatuh kembali ke Scan berfilter untuk "menemukan proyek-proyek sebuah workspace" membuang modelnya dan membaca seluruh tabel — jebakan yang dibahas di Query vs Scan.

Jika Anda benar-benar perlu mendaftarkan proyek lintas workspace (misalnya, semua proyek status = ACTIVE secara global), tabel dasar tak bisa menjawab itu — partition key-nya ter-scope ke workspace.

Itu tugas untuk sebuah secondary index yang me-repartisi proyek pada atribut berbeda, bukan untuk membentuk ulang relasi ini.

Langkah selanjutnya

Modelkan pola aksesnya, encode induk ke dalam partition key anaknya, dan pembacaan one-to-many menjadi satu Query. Bangun dan validasi kondisi key dengan DynamoDB Expression Builder — dan jika Anda lebih suka memulai dari pola aksesnya sendiri, alat Single-Table Design gratis menyusun draf rencana PK/SK/GSI dengan contoh item.

Lalu unduh DynoTable untuk memuat skema ini, menjelajahi koleksi Item workspace→proyek secara langsung, dan memastikan setiap query melakukan tepat satu pembacaan. Jika Anda lebih suka melihat workspace dan proyek sebagai tampilan relasional yang tergabung, SQL Workbench DynoTable menjalankan JOIN itu juga.

Diperbarui

Coba desain ini secara interaktif

Sketsakan entitas dan pola akses Anda di tool DynamoDB Single-Table Design gratis — ia menyarankan template key PK/SK, mempratinjau item collection, dan menunjukkan pola mana yang membutuhkan GSI.

Buka tool Single-Table Design