dynamoのupdateItemで条件付き加算処理をやろうとしたらハマったメモ

  • updateItemで属性値を加減算したい
  • レコードがない時は新規追加にしたい

ということをやろうとして色々ハマって頑張った割に使わなくなったので実装例を備忘録に残します。

やろうとしていることは「updated_atが更新されている場合はidのレコードのvalue++、更新時刻も更新する」です。

function test_add(table_name, id, updated_at)
        return new Promise(function(resolve, reject) {
            const params = {
                Key: {
                    _id: {S: id},
                },
                UpdateExpression: 'SET value = if_not_exists(value, :zero) + :one, updated_at = :updated_at',
                ConditionExpression: 'attribute_not_exists(updated_at) OR updated_at < :updated_at',
                ExpressionAttributeValues: {
                    ':updated_at': {N: updated_at},
                    ':zero': {N: '0'},
                    ':one': {N: '1'},
                }
                TableName: table_name
            };
             const dynamodb = new AWS.DynamoDB({region:regionId});
            dynamodb.updateItem(params, function(err, data) {
                if (err) return reject(err);    // an error occurred
                                else     return resolve(data);
            });
        });

主にidに対応するレコードがない場合に、

  • UpdateExpression内で、ADDとSETは混在できない(※エラーで弾かれただけでよく読んでないんですが、ホントにだめなんですかね…)
  • よってインクリメントの方もSETで書く必要がある
  • インクリメント時に更新する元の属性値を引っ張ろうとした時に if_not_exists() でデフォルト値を書いてないと「そんな属性無いよ」と怒られる
  • 更新条件の前に attribute_not_exists() OR ... がないと「そんな属性無いよ」と怒られる

ので、こんな対応が必要になりました。