読者です 読者をやめる 読者になる 読者になる

カマカマの雑草ブログ

個人の日記です

AWS DynamoDBでupdateItem時のInvalid UpdateExpressionについて

AWS初心者なので初投稿です。

問題

AWS lambdaでDynamoDBのAtomic Counterに対してのincrementを行う以下の様なNode.jsのスクリプトを書いた。

var doc = require('dynamodb-doc');
var dynamo = new doc.DynamoDB();

exports.handler = function(event, context) {
    var params = {
        TableName: "MicroQuasar",
        Key: { 
            "id" : { "N" : "1" }
        },
        ExpressionAttributeNames: {'#Q': 'Quantity' },
        ExpressionAttributeValues: {":i": { "N" : "1" } },
        UpdateExpression: 'SET #Q = #Q + :i'
    };
    
    dynamo.updateItem(params, function(err, data) {
        if(err) {
            context.done('error' + err);
        } else {
            context.succeed(data);
        }
    });
};

これをAWSコンソール上でTestボタンを押して検証するとInvalid UpdateExpressionと言われる。

{
  "errorMessage": "errorValidationException: Invalid UpdateExpression: Incorrect operand type for operator or function; operator or function: +, operand type: M"
}

原因

updateItem実行時のキモになるのがparamsで、UpdateExpressionに式をExpressionAttribute〜に属性と値を入れることでDynamoDB内のItemに対してUpdate処理が走る。
そしてこのExpressionAttributeValuesは値の型をKeyにする形で記述する(DynamoDB Jsonとか言うらしい)

参考: Class: AWS.DynamoDB — AWS SDK for JavaScript

だが、この記述だと:iをNumberではなくMapの{ "N" : 1 }と解釈して+operatorとの不整合を起こしてこのエラーになっている。
UpdateExpressionを代入式に変えるとQuantityの中身がNumberからMapになる。

対応

paramsの{ "N" : "1" }という冗長な記述を全部1に置き換えたら動いた。

    var params = {
        TableName: "MicroQuasar",
        Key: { 
            "id" : 1
        },
        ExpressionAttributeNames: {'#Q': 'Quantity' },
        ExpressionAttributeValues: {":i": 1 },
        UpdateExpression: 'SET #Q = #Q + :i'
    };

自分の書き方が誤りだったのか、どっかドキュメントの記載を見落としていたのか、という可能性は大いにありつつ、もし仕様変更とかならドキュメントに反映してくれないと流石につらい。 このエラーメッセージはまだ良い方で、スキーマがなんか違うよ、みたいなログだけ吐かれると初学者には厳しいものがある。

結局自分が悪かったのか、AWS側の不備だったのかまでがちょっと分からなかったので、取り敢えずこうしたら動いたぜという記録で残しておく。