バッチ処理をNode.js + TypeScriptで作成しており、そのバッチをECS on Fargateで起動しAWS DynamoDBから最新のデータを1件のみ取得する方法を紹介します。
その中でハマったポイントがいくつもあったため、同じ轍を踏むことがないようポイントをまとめておきます。
TL;DR
import * as AWS from 'aws-sdk';
import { DocumentClient } from 'aws-sdk/clients/dynamodb';
AWS.config.credentials = new AWS.ECSCredentials({
httpOptions: { timeout: 5000 }, // 5 second timeout
maxRetries: 10, // retry 10 times
});
const dynamodb = new AWS.DynamoDB();
(async () => {
const params: DocumentClient.QueryInput = {
TableName: "Hoge",
KeyConditionExpression: "Code = :number",
ExpressionAttributeValues: {
":number": { "N": "1111" }
},
ScanIndexForward: false,
Limit: 1
};
const data = await dynamodb.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 = new AWS.ECSCredentials({
httpOptions: { timeout: 5000 }, // 5 second timeout
maxRetries: 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件のみ取得することが可能です。
const params: 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" }
},
おわりに
今回紹介した方法は調べながらトライアンドエラーで解決まで持っていったので、もっと良い方法があるかも知れません。
見識の広い方はコメント頂けると助かります🙏