LoginSignup
4

posted at

updated at

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

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してあげると良さそうです。

ご参考までに。

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
What you can do with signing up
4