Lambda(node.js)で、DynamoDBから超膨大なレコードを取得するプログラムを開発していました。
1分単位でクエリを実行して、レコードを小分け取得するようにしたのですが、
その際にプロパティを初期化できていなかったため、標題のエラーが発生したようです。
っていうことが、以下の記事を見てわかりました
具体的な対策は delete params["ExclusiveStartKey"];
みたいな感じで
プロパティを消せば良いです。
すっごく長いですが、備忘録を兼ねてソースコードを掲載します
try {
var ENV = require('dotenv').config();
var AWS = require('aws-sdk');
AWS.config.update({ region: process.env['AWS_DYNAMO_DB_REGION'] });
var docClient = new AWS.DynamoDB.DocumentClient({ apiVersion : '2012-08-10' });
}
catch(ex){
console.error(ex);
}
var globalSecondaryIndexes = [{
key : 'dummy',
index : 'dummy-created_at-index',
}];
var primaryKeys = {
partitionKey : 'log_id',
sortKey : 'created_at'
};
async function getBulk(runTime = null)
{
var myRunTime = runTime ? runTime : new Date();
var myQuery = "#partitionKey = :partitionVal AND #rangeKey BETWEEN :rangeStart and :rangeEnd";
var params = {
TableName: process.env['AWS_DYNAMO_DB_ACCESS_LOG_TABLE_NAME'],
IndexName : globalSecondaryIndexes[0].index,
ExpressionAttributeNames : {
"#partitionKey" : globalSecondaryIndexes[0].key,
"#rangeKey" : primaryKeys.sortKey
},
ExpressionAttributeValues : {
":partitionVal" : 1,
":rangeStart" : 0,
":rangeEnd" : 0
},
KeyConditionExpression : myQuery
};
var results = new Object();
var dateRanges = [
{
"start" : 1586762880,
"end" : 1586762939,
},
{
"start" : 1586762940,
"end" : 1586762999,
}
];
try {
for(var i in dateRanges){
var dateRange = dateRanges[i];
params["ExpressionAttributeValues"][":rangeStart"] = dateRange["start"];
params["ExpressionAttributeValues"][":rangeEnd"] = dateRange["end"];
delete params["ExclusiveStartKey"]; // <-- ★★★★★★ これ!! ★★★★★★
var result = await get(params); // Array.object
results[dateRange["start"]] = result;
}
return results; // Object.Array.object
}
catch(ex){
console.error("Whoops, looks like something went wrong.");
console.error(ex);
throw new Error(ex);
}
};
async function get(params)
{
try {
// 初回のクエリ発行
var response = await queryGet(params);
var results = response.data; // Array.object
// 二回目以降のクエリ発行
while(response.LastEvaluatedKey){
params.ExclusiveStartKey = response.LastEvaluatedKey;
response = await queryGet(params);
// オブジェクトをマージ
Array.prototype.push.apply(results, response.data);
}
// オブジェクトを返す
return results; // Array.object
}
catch(ex){
myFunc.logError("Whoops, looks like something went wrong.");
myFunc.logError(ex);
throw new Error(ex);
}
};
function queryGet(parameter)
{
return new Promise((resolve, reject) => {
docClient.query(parameter, (err, data) => {
if(err){
console.error(err);
reject(err);
}
else {
if(data.LastEvaluatedKey){ // 全件取得できていない場合、最後の取得位置を通知して再帰処理を行う
resolve({ data: data.Items, count: data.Count, LastEvaluatedKey: data.LastEvaluatedKey });
}
else { // 初回または最後の取得処理時
resolve({ data: data.Items, count: data.Count });
}
}
});
});
};