Last active
April 7, 2021 21:49
-
-
Save danibrear/364b05da796a3c9f8ed956d10ebf3bf9 to your computer and use it in GitHub Desktop.
This is an example migration for adding a status attribute to a hypothetical Todo table.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable @typescript-eslint/no-var-requires */ | |
/** | |
* How to run: | |
* - export AWS_PROFILE | |
* - export AWS_REGION=us-east-1 | |
*/ | |
const DynamoDB = require("aws-sdk/clients/dynamodb"); | |
const dynamodb = new DynamoDB(); | |
const DocumentClient = new DynamoDB.DocumentClient(); | |
const IS_DEV = true; | |
// CHANGE THIS TO THE CORRECT TABLE NAME | |
const TABLE_PREFIX = "Todo"; | |
const PROD_EXT = "prod"; | |
const DEV_EXT = "develop"; | |
/** | |
* Gets the table name for the environment specified above. This makes it | |
* so we dont have to hard-code the amplify random id added to the table name. | |
* @returns a string of the table name or null | |
*/ | |
const getTable = async () => { | |
const tables = await dynamodb.listTables().promise(); | |
if (tables.TableNames) { | |
const postfix = IS_DEV ? DEV_EXT : PROD_EXT; | |
const filtered = tables.TableNames.filter( | |
(tn) => tn.startsWith(`${TABLE_PREFIX}-`) && tn.endsWith(`-${postfix}`), | |
); | |
if (filtered && filtered.length > 0) { | |
return filtered[0]; | |
} | |
return null; | |
} else { | |
return null; | |
} | |
}; | |
// THIS IS WHERE THE PROCESSING HAPPENS | |
const processItems = async (tableName, records) => { | |
try { | |
return await Promise.allSettled( | |
records.map(async (todo) => { | |
// Put processing logic here... | |
await DocumentClient.update({ | |
TableName: tableName, | |
Key: { id: todo.id }, | |
UpdateExpression: "set status = :status", | |
ExpressionAttributeValues: { | |
":status": "complete", | |
}, | |
ReturnValues: "UPDATED_NEW", | |
}).promise(); | |
console.log("Updated todo", todo.id); | |
}), | |
); | |
} catch (e) { | |
console.log("[ERROR] error updating record:", e); | |
return []; | |
} | |
}; | |
const main = async () => { | |
const tableName = await getTable(); | |
console.log("[INFO] changing", tableName); | |
let nextToken = null; | |
let changed = 0; | |
do { | |
const results = await DocumentClient.scan({ | |
TableName: tableName, | |
Limit: 500, | |
ExclusiveStartKey: nextToken, | |
}).promise(); | |
if (results.Items) { | |
changed += (await processItems(tableName, results.Items)).length; | |
console.log("Done with", changed, "items"); | |
} else { | |
break; | |
} | |
if (results.LastEvaluatedKey) { | |
nextToken = results.LastEvaluatedKey; | |
} else { | |
break; | |
} | |
} while (nextToken); | |
console.log("UPDATED", changed, "records."); | |
}; | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Yep. If there are more than 500 records, nextToken will get set to the last evaluated key. If there are less than 500 records, when nextToken is set to null on line 70 it will never get overridden Therefore it will run on the less than 500 items and the do...while loop will exit.