Condition Expression DynamoDB
Sebuah condition expression adalah predikat yang dievaluasi DynamoDB pada Item yang
ada sebelum ia mengcommit penulisan Anda. Jika predikatnya false, penulisan
ditolak dan tak ada yang berubah. Ia adalah hal terdekat yang DynamoDB punya dengan
klausa WHERE pada sebuah penulisan — dan satu-satunya cara aman menegakkan sebuah
invarian.
Bagaimana cara kerja condition expression DynamoDB?
Sebuah condition expression adalah predikat yang dievaluasi DynamoDB di sisi server terhadap Item saat ini sebelum mengcommit sebuah penulisan. Jika ia true, penulisan dilanjutkan; jika false, penulisan ditolak dengan ConditionalCheckFailedException dan tak ada yang berubah. Ia melipat pengecekan dan mutasi menjadi satu operasi atomik, sehingga caller bersamaan tak bisa berlomba dengan pembacaan basi.
- Ia adalah guard, bukan filter.
ConditionExpressionberjalan di sisi server pada Item saat ini; hasil false menggagalkan penulisan denganConditionalCheckFailedException. - Ia menggantikan read-then-write. Tanpa round trip
SELECTlaluUPDATE— pengecekan dan mutasi adalah satu operasi atomik, jadi dua caller tak bisa berlomba. - Gratis untuk menolak, tidak gratis untuk berjalan. Conditional write yang gagal tetap mengonsumsi write capacity. Jaminannya berharga sama dengan penulisan yang diblokirnya.
Datang dari SQL, Anda akan membaca barisnya, memeriksanya di kode aplikasi, lalu memperbarui. Di DynamoDB celah antara baca dan tulis itu adalah bug korupsi-data yang menunggu caller bersamaan. Condition expression menutup celahnya.
Di mana mereka berlaku
Anda melampirkan ConditionExpression ke PutItem, UpdateItem, DeleteItem, dan
setiap aksi di dalam TransactWriteItems. Ia bukan bagian dari Query atau
Scan — keduanya menggunakan FilterExpression, hal berbeda di jalur baca.
Perbedaan itu sering membingungkan orang, jadi tepatlah:
ConditionExpression | FilterExpression | |
|---|---|---|
| Jalur | Penulisan (Put/Update/Delete) | Pembacaan (Query/Scan) |
| Efek saat gagal | Menolak seluruh penulisan | Menjatuhkan Item dari hasil |
| Melihat | Item saat ini, pra-penulisan | Tiap Item kandidat, pasca-pembacaan |
| Biaya | Penulisan gagal tetap ditagih | Item terfilter tetap ditagih untuk pembacaan |
Keduanya berjalan di sisi server. Bedanya adalah apa yang dilakukan "false": sebuah kondisi membatalkan mutasi; sebuah filter sekadar menyembunyikan baris yang sudah Anda bayar untuk dibaca. (AWS: Condition Expressions)
Fungsi yang benar-benar akan Anda pakai
Bahasa kondisinya kecil. Para pekerja kerasnya:
attribute_exists(path)/attribute_not_exists(path)— apakah atribut ini ada pada Item? Idiom klasik untuk "buat hanya jika absen" / "perbarui hanya jika ada".- Komparator —
=,<>,<,<=,>,>=— terhadap sebuah nilai atau atribut lain. attribute_type,begins_with,contains,size— pengecekan tipe dan string/set.BETWEEN … AND …,IN (…)— rentang dan keanggotaan.AND,OR,NOT, tanda kurung — untuk menggabungkan yang di atas.
attribute_not_exists pada partition key adalah cara kanonis membuat PutItem
berperilaku seperti insert yang takkan menimpa Item yang ada — DynamoDB tak punya op
"insert" terpisah, jadi kondisinya adalah semantik insert-nya.
(AWS: Comparison Operator and Function Reference)
Contoh nyata: menjaga sebuah ledger dari overdraft
Ambil sebuah ledger bank. Setiap akun adalah satu Item:
PK = "ACCT#a7f3"
SK = "BALANCE"
clearedCents = 50000
holdCents = 0Invariannya: sebuah debit tak boleh pernah mendorong saldo tersedia di bawah nol, dan Anda tak boleh pernah mendebit akun yang tak ada. Dua aturan, keduanya dapat ditegakkan di dalam penulisan itu sendiri.
Cara yang salah (footgun-nya)
GetItem ACCT#a7f3 / BALANCE → clearedCents = 50000
if (50000 >= 30000) ... ← pengecekan sisi-app
UpdateItem SET clearedCents = 20000
Di antara GetItem dan UpdateItem, debit kedua bisa membaca 50000 yang sama,
lolos pengecekannya sendiri, dan ikut menulis. Keduanya berhasil; akun menjadi
negatif. Ini adalah read-modify-write race, dan validasi sisi-app sebanyak apa pun
tak memperbaikinya — pengecekan dan penulisan adalah operasi terpisah.
Cara yang benar
Lipat pengecekan ke dalam penulisan. Debit 30000 sen, kondisional pada akun yang ada dan memegang cukup:
UpdateItem ACCT#a7f3 / BALANCE
SET clearedCents = clearedCents - :amt
ConditionExpression:
attribute_exists(PK) AND clearedCents >= :amtdengan :amt = 30000. Jika saldonya terlalu rendah, atau Item-nya tak pernah
dibuat, DynamoDB menolak penulisan dengan ConditionalCheckFailedException dan saldo
tak tersentuh. Debit bersamaan entah melihat saldo asli dan diperiksa terhadapnya,
atau melihat yang sudah diperbarui — tak pernah pembacaan basi yang ia bertindak
atasnya.
Anda bisa membangun dan menyalin expression persisnya — nama, nilai, dan semuanya —
dengan DynamoDB expression builder alih-alih
merakit tangan peta ExpressionAttributeValues.
Menginspeksi guard di DynoTable
Saat conditional write gagal, Anda ingin melihat keadaan nyata Item, bukan
menebaknya. Tarik Item akun itu dan baca clearedCents langsung.

Baca penolakannya, jangan retry membabi buta
ConditionalCheckFailedException bukan error transien — meretry penulisan yang sama
tak mengubah apa pun. Ia berarti sebuah aturan bisnis terpicu: dana tak cukup, create
duplikat, versi basi. Munculkan ia sebagai hasil domain, bukan gangguan infra.
Dua hal membuat kegagalan dapat di-debug:
ReturnValuesOnConditionCheckFailure: ALL_OLD— DynamoDB mengembalikan Item saat ini berdampingan dengan kegagalan, jadi Anda bisa menampilkan "saldo 20000, Anda minta 30000" tanpa pembacaan kedua. (AWS: Working with Items)- Membedakan kedua alasan kegagalan.
attribute_exists(PK) AND clearedCents >= :amtmeruntuhkan "tak ada akun" dan "tak ada dana" menjadi satu exception. Jika caller perlu membedakannya, pecah menjadi dua penulisan atau inspeksi Item yang dikembalikan.
Optimistic locking adalah trik yang sama
Pola version-number hanyalah condition expression yang memakai topi berbeda. Simpan
atribut version; setiap penulisan menegaskan versi yang Anda baca dan menaikkannya:
UpdateItem ACCT#a7f3 / BALANCE
SET clearedCents = :new, version = :next
ConditionExpression: version = :seenJika penulis lain bergerak lebih dulu, version = :seen false, penulisan ditolak,
dan Anda membaca ulang dan retry. Inilah cara DynamoDB melakukan concurrency control
tanpa lock — tegaskan apa yang Anda lihat, gagal jika ia bergerak. (AWS: Optimistic
Locking with Version Number)
Jebakan dan langkah berikutnya
- Nama yang bentrok dengan reserved word.
status,size,name, dan ~570 lainnya adalah reserved. Aliaskan mereka denganExpressionAttributeNames(#s = status) atau expression Anda diam-diam gagal di-parse. - Sebuah kondisi tak bisa mereferensikan Item lain. Ia hanya melihat Item yang
sedang ditulis. Invarian lintas-Item butuh
TransactWriteItemsdenganConditionExpressionper-aksi, atau sebuahConditionCheckterhadap Item sentinel. - Penulisan gagal tetap memakan WCU. Guard yang menolak 90% waktu tetap menagih penolakan itu. Asuransi murah, tetapi tidak gratis.
Untuk memodelkan key yang dijalani guard ini, lihat single-table design dan Query vs Scan. Saat Anda siap menerbitkan conditional write terhadap data nyata, unduh DynoTable dan jalankan mereka terhadap tabel Anda sendiri.


