Menengah5 menit baca

Key Condition Expression DynamoDB

Key condition expression adalah KeyConditionExpression yang Anda berikan ke sebuah Query — satu-satunya bagian request yang DynamoDB gunakan untuk menemukan item. Segalanya yang lain (filter, projection) berjalan setelah pembacaan sudah dihitung.

Apa itu key condition expression di DynamoDB?

Sebuah key condition expression adalah KeyConditionExpression pada sebuah Query yang memberi tahu DynamoDB Item mana yang harus dibaca. harus berupa kesetaraan (PK = :v); mengambil satu operator range — =, <, <=, >, >=, BETWEEN, atau begins_with. Ia memutuskan apa yang dibaca dan ditagih, tidak seperti sebuah filter.

  • harus berupa kesetaraan. PK = :v dan tidak lebih — tanpa range, tanpa begins_with, tanpa IN. DynamoDB meng-hash-nya untuk menemukan satu partisi.
  • mengambil operator range. =, <, <=, >, >=, BETWEEN, atau begins_with — di sinilah Anda mengiris sebuah .
  • Ia bukan filter. Sebuah key condition memutuskan apa yang dibaca dan ditagih; sebuah FilterExpression hanya memangkas hasil setelah Anda membayar pembacaannya.
  • Sort key terurut byte. Operator range membandingkan secara leksikografis, jadi cara Anda memformat string sort key adalah kekuatan query Anda.

Mengapa partition key dikunci ke kesetaraan

DynamoDB menyimpan Item dengan meng-hash partition key ke partisi fisik. Sebuah hash memberi Anda satu lokasi, bukan range — jadi tidak ada yang bisa dipindai melintasi.

Itulah mengapa PK > :v atau begins_with(PK, :v) ditolak mentah-mentah. Mesinnya tidak bisa menjawab "semua partisi yang key-nya dimulai dengan X" tanpa membaca seluruh tabel, yang persis merupakan Scan yang dibangun untuk dihindarinya.

Datang dari SQL, ini terasa terbalik: WHERE id LIKE 'order%' sepele di Postgres. Di DynamoDB partition key adalah sebuah alamat, bukan kolom yang bisa dicari.

Sort key adalah tempat kekuatan berada

Dalam satu partisi, Item disimpan terurut berdasarkan sort key. Pengurutan itulah yang dieksploitasi operator range — DynamoDB melompat ke sebuah posisi dan membaca maju.

OperatorMembacaGunakan untuk
SK = :vSatu Item persisAnak spesifik berdasarkan key-nya
SK < / <= / > / >= :vSatu irisan terbuka"Segalanya setelah titik ini"
SK BETWEEN :a AND :bRange tertutup (inklusif)Jendela terbatas — range tanggal
begins_with(SK, :p)Irisan prefixTipe atau hierarki di bawah PK

Tidak ada LIKE, tidak ada CONTAINS, tidak ada ENDS_WITH pada key. Pencocokan substring dan sufiks tidak terurut byte, jadi mereka akan memaksa pembacaan penuh — secara desain, API tidak akan membiarkan Anda. Pencocokan substring ada via contains() dalam sebuah FilterExpression (di mana Anda sudah membayar pembacaannya); pencocokan sufiks tidak tersedia di sisi server sama sekali — simpan key yang dibalik atau filter di sisi klien. (AWS: Key condition expressions)

Contoh nyata: pesan dalam aplikasi chat

Katakanlah Anda membangun chat berbasis channel. Satu tabel, dipartisi berdasarkan channel, diurutkan berdasarkan waktu pesan. Key schema awal:

  • Partition key ChannelRefCH#{channelId}
  • Sort key PostedAt — timestamp ISO-8601, MSG#2026-06-23T14:05:00Z

Prefix MSG# menjaga baris pesan tetap dapat diurutkan dan berbeda dari tipe baris lain yang mungkin Anda ko-lokasikan di bawah channel yang sama (config yang di-pin, keanggotaan).

Muat pesan terkini sebuah channel. Hanya partition key, terbaru dulu:

KeyConditionExpression      ChannelRef = :ch
ExpressionAttributeValues   { ":ch": "CH#general" }
ScanIndexForward            false

ScanIndexForward: false menjelajahi koleksi yang terurut secara terbalik — cara murah untuk mendapat "paling terkini dulu" tanpa mengurutkan di sisi klien.

Hari spesifik dengan begins_with. Karena timestamp adalah sort key dan disimpan sebagai teks, prefix tanggal adalah irisan yang bersih:

KeyConditionExpression  ChannelRef = :ch AND begins_with(PostedAt, :day)
:ch    "CH#general"
:day   "MSG#2026-06-23"

Itu membaca setiap pesan pada 2026-06-23 dan tidak lain — DynamoDB melompat ke prefix dan berhenti saat jatuh dari ujung. Ini hanya bekerja karena prefix adalah left-anchor sejati dari string yang terurut byte.

Jendela presisi dengan BETWEEN. Untuk "pesan selama jam 14:00", sebuah range inklusif mengalahkan prefix:

KeyConditionExpression  ChannelRef = :ch AND PostedAt BETWEEN :lo AND :hi
:ch    "CH#general"
:lo    "MSG#2026-06-23T14:00:00Z"
:hi    "MSG#2026-06-23T14:59:59Z"

BETWEEN inklusif pada kedua batas, jadi pilih endpoint Anda dengan sengaja — sebuah off-by-one di sini diam-diam menjatuhkan atau menggandakan pesan tepi.

Anda bisa merangkai dan menyalin salah satu expression ini, dengan map ExpressionAttributeValues yang terisi untuk Anda, di expression builder DynamoDB — praktis untuk mendapatkan sintaks begins_with dan BETWEEN benar pada percobaan pertama.

Builder ini di-preset ke query pk = … AND begins_with(sk, …) — ubah operatornya untuk melihat KeyConditionExpression diperbarui:

Bangun request Anda
Kode yang dihasilkan
new QueryCommand({
  "TableName": "AuditLog",
  "KeyConditionExpression": "#hashKey = :hashKeyValue AND begins_with(#rangeKey, :rangeKeyValue)",
  "ExpressionAttributeNames": {
    "#hashKey": "pk",
    "#rangeKey": "sk"
  },
  "ExpressionAttributeValues": {
    ":hashKeyValue": {
      "S": "TENANT#acme"
    },
    ":rangeKeyValue": {
      "S": "EVENT#2026-06"
    }
  }
})

Lihat di DynoTable

Jalankan key condition yang sama terhadap partisi channel nyata. Begitu Anda mengatur filter partition-key, DynoTable menerbitkan sebuah Query — jadi Anda memuat hanya irisan itu, bukan seluruh koleksi.

Jebakannya: mengacaukan key condition dengan filter

Kesalahan yang mahal adalah meraih FilterExpression untuk melakukan tugas sebuah key. Sebuah filter bahkan tidak bisa mereferensikan PostedAt — ia adalah sort key, dan DynamoDB menolak filter pada atribut key dengan ValidationException. Jadi workaround-nya adalah menduplikasi tanggal ke atribut non-key biasa (MessageDate) dan memfilter pada itu:

KeyConditionExpression   ChannelRef = :ch
FilterExpression         begins_with(MessageDate, :day)

Ini terlihat setara dengan key condition begins_with di atas dan mengembalikan baris yang sama — tetapi ia membaca seluruh partisi channel dulu, lalu membuang segalanya di luar harinya. Anda ditagih untuk pembacaan penuh.

Filter tidak pernah mengurangi biaya baca. Mereka berjalan setelah DynamoDB menghitung Item-nya, bumerang yang sama dengan sebuah Scan yang difilter. Jika sebuah predikat bisa masuk ke key condition, di sanalah tempatnya.

Perbaikannya di hulu: jika sebuah pola akses tidak bisa diekspresikan sebagai satu kesetaraan PK plus sebuah range sort-key, itu sinyal pemodelan. Entah bentuk ulang sort key-nya, atau tambahkan indeks yang di-key untuk pola itu — lihat GSI vs LSI dan single-table design untuk cara menata key-nya.

Jebakan dan langkah selanjutnya

  • Partition key selalu =. Tanpa range, selamanya. Jika Anda butuh range melintasi partisi, Anda sudah melampaui satu Query.
  • Satu kondisi sort-key per query. Anda tidak bisa AND dua predikat sort-key; pilih BETWEEN atau begins_with, bukan keduanya.
  • Reserved word butuh alias. Key bernama Timestamp atau Name harus memakai ExpressionAttributeNames (#ts), atau query error. (AWS: reserved words)
  • BETWEEN inklusif. Kedua endpoint dicocokkan — desain batas Anda sesuai itu.

Draf key condition Anda di expression builder, lalu coba DynoTable untuk menjalankannya terhadap tabel Anda sendiri dan melihat persis irisan mana yang dikembalikan setiap key condition.

Diperbarui