LoginSignup
18
9

More than 1 year has passed since last update.

【DynamoDB】updateItemで新規項目を追加しないようにする 〜条件付き書き込み(ConditionExpression)を使って〜

Last updated at Posted at 2020-06-02

DynamoDBのupdate処理で、テーブルに存在しない項目を指定すると、新規項目としてテーブルに追加されてしまいます(UpdateItem)。
条件付き書き込み(ConditionExpression)を使用し、updateで存在しない項目を指定した時に、テーブルへの追加を防ぎ、何も変化しない状態になるよう実装します。

環境

  • macOS
  • AWS Cloud9
  • Node.js 12

AWS.DynamoDB.DocumentClient

JavascriptでDynamoDBを操作するとき、AWS.DynamoDBを使う方法とAWS.DynamoDB.DocumentClientを使う方法の2パターンがあるのですが、AWS.DynamoDB.DocumentClientを使う方が、DBを操作するときにデータの型を指定せずにコードを書くことができて便利なので、今回はこちらを使用しています。
AWS.DynamoDBとの違いは、データ型の指定が不要な点と、メソッド名がやや異なる(〇〇Itemが〇〇になる)くらいで、メソッドの具体的な仕様は全く同じと考えて良さそうです(AWS.DynamoDB.DocumentClient 公式ドキュメント)。

実行コード

const AWS = require('aws-sdk');
const DB = new AWS.DynamoDB.DocumentClient();

exports.handler = async(event, context) => {
    const dbParams = {
        TableName: "tableName",
        Key:{
            timestamp: XXXXXX                                
            message: "message"
        },
        ExpressionAttributeNames: {
            '#s': 'status'
        },
        ExpressionAttributeValues: {
            ':status': true
        },
        ReturnValues: 'ALL_NEW', 
        UpdateExpression: 'SET #s = :status',
        ConditionExpression: 'attribute_exists(#s)' // ここで条件を指定
    };
    const data = await DB.update(dbParams).promise();
    return data
}

ここで、

ConditionExpression: 'attribute_exists(#s)' 

によって、「timestamp属性の値がXXXXXX、message属性の値が"message"である項目のうち、statusという属性を持つ項目が存在している場合」のみ、updateが実行されるようになります。
つまり、そもそも指定したtimestampmessageを持つ項目が存在しなければ、何も実行されずに済むということです。

ConditionExpression

ConditionExpressionに使用できる演算子・関数は、
比較演算子: = | <> | < | > | <= | >= | BETWEEN | IN
論理演算子: AND | OR | NOT
関数: attribute_exists | attribute_not_exists | attribute_type | contains | begins_with | size
となっています。(参考:公式ドキュメント

各関数について簡単に説明しておくと、

  • attribute_exists(path):キーで指定した項目にpathという属性が存在する場合に実行
  • attribute_not_exists(path):キーで指定した項目にpathという属性が存在しない場合に実行
  • attribute_type(path, type):pathという属性の値がtypeで指定したデータ型であれば実行
  • begins_with(path, substr):pathという属性の値がsubstrで指定した文字列で始まる場合に実行
  • contains(path, operand):pathという属性の値がoperandを含んでいれば実行
  • size(path):pathで指定した属性のサイズを返す。例えば、size(path) < 3のようにして使う

となっております。
各演算子や関数に関する詳細は、こちらのリファレンスをご覧ください。

実行に失敗したとき

指定したDBの操作がConditionExpressionの制約に反し、実行されなかった場合には、ConditionExpressionという例外が吐かれます。
例外時に何か処理を施したい場合は、try~catchでConditionExpressionをcatchしてあげると良さそうです。

ご参考までに。

18
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
9