Created
October 28, 2021 03:43
-
-
Save tywalch/914a2238d67f6a8f20bf9a744c86d994 to your computer and use it in GitHub Desktop.
Updating GSIs with strings like it's possible with numbers
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
const DynamoDB = require("aws-sdk/clients/dynamodb"); | |
const client = new DynamoDB.DocumentClient({ | |
region: "us-east-1", | |
endpoint: "http://localhost:8000" | |
}); | |
/** | |
* withNumbers demonstrates the update of a "composite" gsi sortkey without knowledge of the current | |
* composite value at the time of update. This works runs without error and operates as expected. | |
*/ | |
async function withNumbers() { | |
const pk = 500; | |
const sk = 200; | |
const table = "with_numbers_example"; | |
// clear prior runs | |
await client.delete({ | |
Key: { pk, sk }, | |
TableName: table | |
}).promise(); | |
// create a new item | |
await client.put({ | |
Item: { | |
number1: 500, | |
number2: 200, | |
number3: 10, | |
number4: 35, | |
number5: 5, | |
pk: 500, | |
sk: 200, | |
gsi1pk: 10, // single attribute "composite", should mirror `number3` | |
gsi1sk: 40, // two attribute composite, should mirror `number4` + `number5` | |
}, | |
TableName: table | |
}).promise(); | |
// An update to `number5` should update `number5` (the attribute itself) and recalculate `gsi1sk` | |
await client.update({ | |
UpdateExpression: "SET #gsi1sk = :number5 + #number4, #number5 = :number5 + #number4", | |
ExpressionAttributeNames: { | |
"#gsi1sk": "gsi1sk", | |
"#number4": "number4", | |
"#number5": "number5", | |
}, | |
ExpressionAttributeValues: { | |
":number5": 10, | |
}, | |
Key: { pk, sk }, | |
TableName: table | |
}).promise(); | |
const results = await client.query({ | |
IndexName: "gsi1pk-gsi1sk-index", | |
KeyConditionExpression: "#pk = :pk and #sk = :sk", | |
ExpressionAttributeNames: { | |
"#pk": "gsi1pk", | |
"#sk": "gsi1sk" | |
}, | |
ExpressionAttributeValues: { | |
":pk": 10, // still equal to original `number3` value | |
":sk": 45 // now equal original `number4` value (35) + new `number5` value (10) | |
}, | |
TableName: table | |
}).promise(); | |
console.log(JSON.stringify(results, null, 4)); | |
} | |
/** | |
* withStrings demonstrates the update of a "composite" gsi sortkey without knowledge of the current | |
* composite value at the time of update. This uses the same approach as `withNumbers` but does not | |
* have comparable functionality. | |
*/ | |
async function withStrings() { | |
const pk = "mdinescu"; | |
const sk = "#user"; | |
const table = "with_strings_example"; | |
// clear prior runs | |
await client.delete({ | |
Key: { pk, sk }, | |
TableName: table | |
}).promise(); | |
// create a new item | |
await client.put({ | |
Item: { | |
username: "mdinescu", | |
team: "alexa_games", | |
city: "irvine", | |
state: "ca", | |
pk: "mdinescu", | |
sk: "#user", | |
gsi1pk: "alexa_games", // single attribute "composite", should mirror `team` | |
gsi1sk: "irvine#ca", // two attribute composite, should mirror `city` + `state` | |
}, | |
TableName: table | |
}).promise(); | |
// An update to `city` should update `city` (the attribute itself) and recalculate `gsi1sk` | |
// Note: doesn't include "#" delimiter to keep things close to the original `withNumbers` example. | |
await client.update({ | |
UpdateExpression: "SET #gsi1sk = :city + #state, #city = :city + #state", | |
ExpressionAttributeNames: { | |
"#gsi1sk": "gsi1sk", | |
"#city": "city", | |
"#state": "state", | |
}, | |
ExpressionAttributeValues: { | |
":city": "oakland", | |
}, | |
Key: { pk, sk }, | |
TableName: table | |
}).promise(); | |
const results = await client.query({ | |
IndexName: "gsi1pk-gsi1sk-index", | |
KeyConditionExpression: "#pk = :pk and #sk = :sk", | |
ExpressionAttributeNames: { | |
"#pk": "gsi1pk", | |
"#sk": "gsi1sk" | |
}, | |
ExpressionAttributeValues: { | |
":pk": "alexa_games", // still equal to original `team` value | |
":sk": "oakland#ca" // now equal new `city` value ("oakland") + original `state` value ("ca") | |
}, | |
TableName: table | |
}).promise(); | |
console.log(JSON.stringify(results, null, 4)); | |
} | |
async function main() { | |
await withNumbers(); | |
await withStrings(); | |
} | |
main().catch(console.log); |
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
{ | |
"KeySchema":[ | |
{ | |
"AttributeName":"pk", | |
"KeyType":"HASH" | |
}, | |
{ | |
"AttributeName":"sk", | |
"KeyType":"RANGE" | |
} | |
], | |
"AttributeDefinitions":[ | |
{ | |
"AttributeName":"pk", | |
"AttributeType":"N" | |
}, | |
{ | |
"AttributeName":"sk", | |
"AttributeType":"N" | |
}, | |
{ | |
"AttributeName":"gsi1pk", | |
"AttributeType":"N" | |
}, | |
{ | |
"AttributeName":"gsi1sk", | |
"AttributeType":"N" | |
} | |
], | |
"GlobalSecondaryIndexes":[ | |
{ | |
"IndexName":"gsi1pk-gsi1sk-index", | |
"KeySchema":[ | |
{ | |
"AttributeName":"gsi1pk", | |
"KeyType":"HASH" | |
}, | |
{ | |
"AttributeName":"gsi1sk", | |
"KeyType":"RANGE" | |
} | |
], | |
"Projection":{ | |
"ProjectionType":"ALL" | |
} | |
} | |
], | |
"BillingMode":"PAY_PER_REQUEST", | |
"TableName": "with_numbers_example" | |
} |
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
{ | |
"KeySchema":[ | |
{ | |
"AttributeName":"pk", | |
"KeyType":"HASH" | |
}, | |
{ | |
"AttributeName":"sk", | |
"KeyType":"RANGE" | |
} | |
], | |
"AttributeDefinitions":[ | |
{ | |
"AttributeName":"pk", | |
"AttributeType":"S" | |
}, | |
{ | |
"AttributeName":"sk", | |
"AttributeType":"S" | |
}, | |
{ | |
"AttributeName":"gsi1pk", | |
"AttributeType":"S" | |
}, | |
{ | |
"AttributeName":"gsi1sk", | |
"AttributeType":"S" | |
} | |
], | |
"GlobalSecondaryIndexes":[ | |
{ | |
"IndexName":"gsi1pk-gsi1sk-index", | |
"KeySchema":[ | |
{ | |
"AttributeName":"gsi1pk", | |
"KeyType":"HASH" | |
}, | |
{ | |
"AttributeName":"gsi1sk", | |
"KeyType":"RANGE" | |
} | |
], | |
"Projection":{ | |
"ProjectionType":"ALL" | |
} | |
} | |
], | |
"BillingMode":"PAY_PER_REQUEST", | |
"TableName": "with_strings_example" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment