AWS SDK for Java (DynamoDBMapper)を使った条件付き書き込み

DynamoDBMapperの概要については以下に書かれています。

docs.aws.amazon.com

DynamoDBMapper はタイプセーフに扱えて便利な反面、素のAWS API(オペレーション)が色々とラップされてしまっているので、以下によく使う利用法を逆引きリファレンスとして整理しました。

(注)確認は AWS SDK for Java のバージョン 1.10.62 で行っています。古いバージョンなので、最新のバージョンでは API が変更されている可能性もあるのでご注意ください。

すべての属性を置き換える

項目を更新する際に、既存の項目を丸ごと置き換える(不要な属性は削除)か、特定の属性だけ書き換えたいかを使い分けたいケースがあります。
通常、前者はputItem、後者はupdateItemといった形でオペレーションを使い分けます。

引数1つだけの save メソッドは putItem 相当の動作になります。

mapper.save(item);

指定した属性だけを更新する(他の属性はそのまま)

保存時の振る舞いについては DynamoDBSaveExpression を使って変更が可能です。

DynamoDBMapperConfig config = new DynamoDBMapperConfig(DynamoDBMapperConfig.SaveBehavior.UPDATE_SKIP_NULL_ATTRIBUTES);
mapper.save(item, config);

item中で非NULLの属性だけが更新されます。

ちなみに、 SaveBehavior には以下の4種類のパターンがあります。詳細はJavaDocを参照してください。

  • UPDATE(デフォルト)
  • UPDATE_SKIP_NULL_ATTRIBUTES
  • CLOBBER
  • APPEND_SET

項目が存在しない場合はエラーにする

putItem, updateItemのどちらも、基本的にはupsert相当の動作になります(キーがあれば更新、なければ追加)。

中途半端な属性だけをもつ項目が追加されてしまっても困るので、項目が存在する場合に限り、更新処理を行いたい場合があります。

その場合、条件式 ( DynamoDBSaveExpression )を利用します。

AttributeValue hashValue = new AttributeValue().withS("Key1");
AttributeValue rangeValue = new AttributeValue().withN(Long.toString(123L));

DynamoDBSaveExpression expression= new DynamoDBSaveExpression()
        .withConditionalOperator(ConditionalOperator.AND)
        .withExpectedEntry("partitionKeyName", new ExpectedAttributeValue()
                .withValue(hashValue)
                .withComparisonOperator(ComparisonOperator.EQ))
        .withExpectedEntry("sortKeyName", new ExpectedAttributeValue()
                .withValue(rangeValue)
                .withComparisonOperator(ComparisonOperator.EQ));

mapper.save(item, expression);

// DynamoDBMapperConfigと組み合わせる場合は以下。
// mapper.save(item, expression, config);

プライマリキー “Key1”, パーティションキー “123” の項目が存在しない場合、 ConditionalCheckFailedException がスローされます。

項目が存在する場合はエラーにする

上の例と逆に、項目が存在しない場合に限り登録を行いたい場合の例です。

DynamoDBSaveExpression expression = new DynamoDBSaveExpression()
        .withExpectedEntry("partitionKeyName", new ExpectedAttributeValue().withExists(false))
        .withConditionalOperator(ConditionalOperator.AND)
        .withExpectedEntry("sortKeyName", new ExpectedAttributeValue().withExists(false));

mapper.save(item, expression);

こちらも違反時は ConditionalCheckFailedException がスローされます。

その他の条件式

上で書いた以外にも、色々な条件式が利用できます。

docs.aws.amazon.com

DynamoDBMapperでも、上記の条件式がすべて利用できるはずですので、必要に応じて DynamoDBSaveExpression を作成していくことになると思います。