はじめに
現状、DynamoDB では、 RDB で言うところのUNIQUE制約
がありません。つまり「UserテーブルでEmailを一意になるように制約をかける」といったことができません。
正確に言うと、ハッシュキー属性にはUNIQUE制約があります。
この記事では、ハッシュキーにはUNIQUE制約があることを利用しつつ、条件付き更新
と トランザクション
を組み合わせて、任意の属性を対象とするUNIQUE制約を実現する方法を紹介しています。
以下のようなDynamoDBの知識を前提としています。
- 項目 と 属性 がなにを指しているのか理解している
- hash-key(とrange-key) を理解している
- 基本的な CRUD 関連の操作方法を理解している
- 条件付き更新を理解している
- トランザクションを理解している
必要に応じて、以下の AWS のドキュメントを参照してください。
UNIQUE制約の実現方法
例えば、以下のような User エンティティがあるとします。
User エンティティをDynamoDBに新規作成する場合、以下の項目を作成する処理をトランザクションで実行します。
- User エンティティ自体を保存する項目(
エンティティ項目
) - UserのEmail属性を UNIQUE属性にするための項目(
UNIQUE制約用項目
)
エンティティ項目
では、EmailやNameなどのエンティティ自体の情報を記録します。
UNIQUE制約用項目
では、UNIQUE制約をかけたい項目をhash-keyとして設定し、条件付き更新で試みます。
例として、Emailに対してUNIQUE制約をかけたい場合を考えます。このとき、UNIQUE制約用項目
を以下の手順で作成します。
- PK(hash-key) を
User#Email#test@example.com
という値で設定。 -
if attribute_not_exists(PK)
で、書き込みを試みる。
以下の図は、UNIQUE制約に引っかかってエラーが起こる場合を示しています。
Bob が test@example.com
で項目を作成した後に、Alice が test@example.com
で項目を作成しようとして失敗します。 Aliceが書き込むときには if attribute_not_exists(PK)
の条件が偽になるからです。
トランザクションで実行された場合、ロールバックが実行され、Aliceの項目作成処理がキャンセルされます。
このようにして、UNIQUE制約を実現しています。
更新と削除の処理について
上記は、新規作成時の処理について解説しました。更新と削除のときにも注意が必要です。
それぞれ以下のような処理を行います。
更新時
更新の場合は、Emailの値を変更する場合のみ UNIQUE制約について考慮する必要があります。
以下の更新処理をトランザクションで実行します。
-
エンティティ項目
のEmail属性の値を更新する - 新しいEmailについて、
if attribute_not_exists(PK)
という条件で書き込みを試みる - 古いEmailについて、
UNIQUE制約用項目
を削除する
削除時
削除の場合は、以下の処理をトランザクションで実行します。
-
エンティティ項目
を削除する -
UNIQUE制約用項目
を削除する
まとめ
現状、DynamoDBでは任意の属性に対してUNIQUE制約をかけることができないので、条件付き更新 と トランザクションを組み合わせて擬似的に実現する方法を紹介しました。
「hash-key に設定できないけどUNIQUE制約を設定したい属性がある」といった場合に、有効な方法であると考えています。デメリットとしては、実装が少し複雑になってしまうところでしょうか。
DynamoDBは、アップデートされるごとに機能が増えたり、機能の制約が緩和されたりするので、将来的に UNIQUE制約を設定できる可能性もあるかもしれません。そうなった場合は、この方法は不要になるでしょう。