Lambda(Node.js)からDynamoDBのテーブルを更新する

Lambda(Node.js)からDynamoDBのテーブルを更新します。

AWS.DynamoDB.DocumentClient()#updateメソッドで更新することができます。このメソッドはAWS.DynamoDB()#updateItemメソッドに委譲するので、指定するパーティションキー(かつ、ソートキー)のデータがあれば更新し、データがなければインサートします。(アップサート)

第一引数にパラメータを入れます。パラメータは以下のとおりです。

TableName テーブル名を指定します
Key パーティションキー、ソートキーを指定します
UpdateExpression 更新する構文を記述します(省略可)
ConditionExpression 更新条件を指定します(省略可)
ExpressionAttributeNames 属性(列名)のバインド変数を指定します(省略可)
ExpressionAttributeValues バインド変数の値を指定します(省略可)

テーブル名とキーのみ必須です。以下、記述例です。

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という属性があります。

Lambda(Node.js)からDynamoDBのテーブルを更新する

ConditionExpressionを指定していませんが、これを指定するとアップサートができなくなります。アップデートのみになります。

上記コードをLambda関数で作成し、テストします。

結果、sampleテーブルは以下のように更新されていることがわかります。

Lambda(Node.js)からDynamoDBのテーブルを更新する

次にソートキーを「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テーブルは以下のように登録されていることがわかります。

Lambda(Node.js)からDynamoDBのテーブルを更新する

Map型の属性を更新する

DynamoDBの属性にはMap型と言うのがあります。DynamoDBのデータを見るとMapと表示されています。

データは、パーティションキーがリンクになっているので、その部分をクリックします。

Lambda(Node.js)からDynamoDBのテーブルを更新する

クリックすると以下のような画面が表示されます。

Lambda(Node.js)からDynamoDBのテーブルを更新する

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には予約語が異常に多いです。

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

参考サイト

スポンサーリンク
  • このエントリーをはてなブックマークに追加
スポンサーリンク

コメントをどうぞ

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA