Lambda(Node.js)からDynamoDBのテーブルを更新する
Lambda(Node.js)からDynamoDBのテーブルを更新する
Lambda(Node.js)からDynamoDBのテーブルを更新します。
AWS.DynamoDB.DocumentClient()#updateメソッドで更新することができます。このメソッドはAWS.DynamoDB()#updateItemメソッドに委譲するので、指定するパーティションキー(かつ、ソートキー)のデータがあれば更新し、データがなければインサートします。(アップサート)
第一引数にパラメータを入れます。パラメータは以下のとおりです。
TableName | テーブル名を指定します |
Key | パーティションキー、ソートキーを指定します |
UpdateExpression | 更新する構文を記述します(省略可) |
ConditionExpression | 更新条件を指定します(省略可) |
ExpressionAttributeNames | 属性(列名)のバインド変数を指定します(省略可) |
ExpressionAttributeValues | バインド変数の値を指定します(省略可) |
AWS SDK for JavaScript v2
テーブル名とキーのみ必須です。以下、記述例です。
var AWS = require("aws-sdk"); AWS.config.update({ region: "us-east-1", // バージニア北部 }); var docClient = new AWS.DynamoDB.DocumentClient(); let params = { TableName: 'sample', // sampleというテーブル名 Key: { 'id' : '1', 'sortkey' : '1'}, // idと言うパーティションキー属性、sortkeyというパーティションキー属性 UpdateExpression: 'set #a = :x', // 属性は#から始まるバインド変数、値は:から始まるバインド変数 ExpressionAttributeNames: {'#a' : 'name'}, // 属性名はname ExpressionAttributeValues: {':x' : 'taro'} // 値はtaro }; docClient.update(params, function(err, data) { if(err) console.log(err); else console.log(data); });
以下がテーブルです。パーティションキーがid,ソートキーがsortkey,nameという属性があります。
ConditionExpressionを指定していませんが、これを指定するとアップサートができなくなります。アップデートのみになります。
上記コードをLambda関数で作成し、テストします。
結果、sampleテーブルは以下のように更新されていることがわかります。
次にソートキーを「2」に変更し、データがない場合、インサートされるかを試します。
var AWS = require("aws-sdk"); AWS.config.update({ region: "us-east-1", // バージニア北部 }); var docClient = new AWS.DynamoDB.DocumentClient(); let params = { TableName: 'sample', // sampleというテーブル名 Key: { 'id' : '1', 'sortkey' : '2'}, // idと言うパーティションキー属性、sortkeyというパーティションキー属性 UpdateExpression: 'set #a = :x', ExpressionAttributeNames: {'#a' : 'name'}, ExpressionAttributeValues: {':x' : 'taro'} }; docClient.update(params, function(err, data) { if(err) console.log(err); else console.log(data); });
これをLambda関数で作成し、テストします。
結果、sampleテーブルは以下のように登録されていることがわかります。
Map型の属性を更新する
DynamoDBの属性にはMap型と言うのがあります。DynamoDBのデータを見るとMapと表示されています。
データは、パーティションキーがリンクになっているので、その部分をクリックします。
クリックすると以下のような画面が表示されます。
map_dataという属性がMap型になっています。Map型の中身は以下です。
"map_data": { "status": "true" }
このマップを更新するには、上記コードのExpressionAttributeValuesを以下のようにオブジェクトに変えてあげれば更新することができます。ちなみにマップの一つの要素だけを更新することも可能です。
ExpressionAttributeValues: {':x' : {'status':'false'}}
UpdateExpressionに直書きして更新したい場合、以下のように記述してみましたが、エラーになりました。
UpdateExpression: 'set #a = {\"status\":\"true\"}'
エラー:Invalid UpdateExpression: Syntax error; token: “{“, near: “= {“”
素直にバインド変数を使った方が良いと思われます。
属性名が予約語の場合、バインド変数を使う
DynamoDBには予約語が異常に多いです。
属性名を予約後にしてしまった場合、UpdateExpresssionにそのまま属性名(予約語)を記述するとエラーとなります。
const AWS = require("aws-sdk"); AWS.config.update({ region: "us-east-1", }); const docClient = new AWS.DynamoDB.DocumentClient(); let params = { TableName: 'sample', Key: { 'id' : '1', 'sortkey' : '1'}, UpdateExpression: 'set datetime = :x', ExpressionAttributeValues: {':x' : '20200101'} }; docClient.update(params,function(err, data) { if(err) console.log(err); else console.log(data); });
エラー:ValidationException: Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: datetime
この為にあるのかな?と思うくらいですが、これを回避するためにExpressionAttributeNamesを使用します。
以下、変更箇所です。
UpdateExpression: 'set #a = :x', ExpressionAttributeNames: {'#a' : 'datetime'},
これでLambdaを実行すると、予約語のdatetimeであっても更新することが確認できます。
パーティションキー、ソートキーは更新できない
RDBでは一応PKは更新可能ですが、PKは更新すべきではありません。
DynamoDBではそもそもパーティションキーとソートキーは更新することができません。
もちろん未指定に更新することもNGです。
エラーメッセージは以下のように出ます。
This attribute is part of the key
ConditionExpression
ConditionExpressionを指定すると、インサートはできなくなります。
updateの引数には以下のように指定したオブジェクトを渡します。
let params = { TableName: 'sample', Key: { 'id' : '1', 'sortkey' : '1'}, UpdateExpression: 'set #a = :x', ExpressionAttributeNames: {'#a' : 'datetime'}, ExpressionAttributeValues: { ':x' : '20200102', ':y' : '3' }, ConditionExpression: 'sortkey = :y' };
この時、ConditionExpressionの条件に合致しない場合、「code: ‘ConditionalCheckFailedException’」のエラーがでます。
AWS SDK for JavaScript v2
.
参考サイト
KHI入社して退社。今はCONFRAGEで正社員です。関西で140-170/80~120万から受け付けております^^
得意技はJS(ES6),Java,AWSの大体のリソースです
コメントはやさしくお願いいたします^^
座右の銘は、「狭き門より入れ」「願わくは、我に七難八苦を与えたまえ」です^^
コメント