バッチ処理をNode.js + TypeScriptで作成しており、そのバッチをECS on Fargateで起動しAWS DynamoDBから最新のデータを1件のみ取得する方法を紹介します。
その中でハマったポイントがいくつもあったため、同じ轍を踏むことがないようポイントをまとめておきます。
TL;DR
import*asAWSfrom'aws-sdk';import{DocumentClient}from'aws-sdk/clients/dynamodb';AWS.config.credentials=newAWS.ECSCredentials({httpOptions:{timeout:5000},// 5 second timeoutmaxRetries:10,// retry 10 times});constdynamodb=newAWS.DynamoDB();(async()=>{constparams:DocumentClient.QueryInput={TableName:"Hoge",KeyConditionExpression:"Code = :number",ExpressionAttributeValues:{":number":{"N":"1111"}},ScanIndexForward:false,Limit:1};constdata=awaitdynamodb.query(params,(err,data)=>{if(err){console.log("Error",err);}else{console.log("Success",data);}}).promise();console.log(data.Items[0].hoge.S);})();
ECSからDynamoDBへアクセスする方法
事前準備
事前にECSに付与するためのIAMロールを作成し、DyanamoDBへの権限を有したポリシーをアタッチしておきます。
次にECSのタスク定義、もしくはタスク実行時にタスクロールに先程作成したIAMロールを付与します。
プログラム
AWS.config.credentials=newAWS.ECSCredentials({httpOptions:{timeout:5000},// 5 second timeoutmaxRetries:10,// retry 10 times});
最新の1件を取得するQuery
始めはDocumentClientを利用していましたが、どうやっても上手くいかず最終的にはDocumentClientを使わない方法に落ち着きました。
※ schemaの不一致とエラーになる
(node:1) UnhandledPromiseRejectionWarning: ValidationException: One or more parameter values were invalid: Condition parameter type does not match schema type
※未だに原因がわかっていないので、コメント頂けると嬉しいです
パラメータの型にはDocumentClient.QueryInput
を指定します。
この辺はググっても全然情報が出なかったので、sdkのGitHubから引っ張ってようやくわかりましたが、どこかに載ってるのかな??🤔
https://github.com/aws/aws-sdk-js/blob/master/lib/dynamodb/document_client.d.ts
最後に最新の1件のみを取得する方法ですが、Sort Keyが設定されている状態でScanIndexForward: false
を指定すると降順でデータを取得できます。
さらにLimit: 1
を指定して、1件のみ取得することが可能です。
constparams:DocumentClient.QueryInput={TableName:"Hoge",KeyConditionExpression:"Code = :number",ExpressionAttributeValues:{":number":{"N":"1111"}},ScanIndexForward:false,// 降順(新しい順)Limit:1// 1件のみ};
ちなみにDynamoDBのNumber型を指定しているカラムも文字列としないとエラーになりましたので、数値が与えられる場合はString型にキャストしたほうが良いみたいです。
Expected params.Item['Code'].N to be a string
ExpressionAttributeValues:{":number":{"N":"1111"}},
おわりに
今回紹介した方法は調べながらトライアンドエラーで解決まで持っていったので、もっと良い方法があるかも知れません。
見識の広い方はコメント頂けると助かります🙏