DynamoDB

Pricing

Reads

1 Read Request Unit: Maximum of 4KB
Read Type
Units
Strongly Consistent
1 Unit
Eventually Consistent Read
1/2 Unit
Transactional Read
2 Units

Writes

1 Write Request Unit: Maximum of 1KB
Write Type
Units
Standard Write Request
1 Unit
Transactional Write
2 Units

Node.js

To store Timestamp:
1
new Date().toISOString()
Copied!

Designing Your Tables

    Unlike traditional RDBMs, DynamoDB groups sorts by partitions.
      Each partition returns sorted result.
    Fields used for partition keys are immutable.
      You cannot change the values for fields which make up the partition key
      Bad idea to use name as the partition key, because you won't be able to change the name of an object.

Gotchas

Naming

For all things naming regarding DynamoDB.
    DynamoDB doesn't allow you to rename tables
    DynamoDB has Reserved Words, so you'll need to use ExpressionAttributeNames to work around them.
    Table names should be prefixed when deploying. Suggested $service-$stage-$table, for example build-my-prod-events
    Index names don’t need to be prefixed.
    Index names can be reused across tables.For example:
      1.
      Table Events, indexname: updated at
      2.
      Table organizations, indexname: updated at

vs RDBMS

DyanmoDB cannot do large "UPDATE queries", for example you cannot do:
1
UPDATE events
2
SET status = "past"
3
WHERE status = "upcoming" AND end_time < NOW();
Copied!
You have to query each individual event. In this scenario, potentially look at storing the status as a Global Secondary Index. For example:
1
const response = await dynamodb.queryPromise({
2
TableName: process.env.EVENTS_TABLE,
3
IndexName: process.env.EVENTS_STATUS_INDEX,
4
KeyConditionExpression: "#s = :status AND #e <= :end_time",
5
ExpressionAttributeNames:{
6
"#s": "status",
7
"#e": "end_time",
8
},
9
ExpressionAttributeValues: {
10
":status": "upcoming",
11
":end_time": new Date().toISOString(),
12
},
13
ProjectionExpression: "id",
14
});
15
16
// We can use either a single BatchWriteItem or multiple UpdateItems
17
const promises = response.Items.map((event) =>
18
dynamodb.updatePromise({
19
TableName: process.env.EVENTS_TABLE,
20
Key: {
21
id: event.id,
22
},
23
UpdateExpression: "SET #s = :status",
24
ExpressionAttributeNames:{
25
"#s": "status",
26
},
27
ExpressionAttributeValues: {
28
":status": "upcoming",
29
},
30
})
31
);
32
33
await Promise.all(promises);
Copied!

Serverless

WARNING: Changing the table name in serverless.yml will drop the table.

DynamoDB Shell

Work around is to use ExpressionAttributeNames and ExpressionAttributeValues
Example of using the keys:
1
dynamodb.query({
2
TableName: process.env.EVENTS_TABLE,
3
IndexName: process.env.EVENTS_STATUS_INDEX,
4
KeyConditionExpression: "#s = :status AND #e <= :end_time",
5
ExpressionAttributeNames:{
6
"#s": "status",
7
"#e": "end_time",
8
},
9
ExpressionAttributeValues: {
10
":status": "upcoming",
11
":end_time": new Date().toISOString(),
12
},
13
ProjectionExpression: "id",
14
});
Copied!
Examples of Reserved Words:
    counter
    name
    source
    url
    uuid
    value

Promises (async/await)

1
const { promisify } = require('util');
2
...
3
dynamodb.putPromise = promisify(dynamodb.put);
4
dynamodb.updatePromise = promisify(dynamodb.update);
5
dynamodb.getPromise = promisify(dynamodb.get);
6
...
7
result = await dynamodb.putPromise({});
8
result = await dynamodb.updatePromise({});
9
result = await dynamodb.getPromise({});
10
Copied!

GetItem

1
// Does not throw an exception if record does not exist
2
const result = await dynamodb.getPromise({});
3
4
if (!result.Item) {
5
// exit early
6
}
Copied!
GetItem cannot be preformed on a Global Secondary Index. You can't use IndexName.

PutItem

Will overwrite values if the key is the same; unless you define a ConditionalExpression
If an item that has the same primary key as the new item already exists in the specified table, the new item completely replaces the existing item. You can perform a conditional put operation (add a new item if one with the specified primary key doesn't exist), or replace an existing item if it has certain attribute values. You can return the item's attribute values in the same operation, using the ReturnValuesparameter.
1
docClient.put(
2
{
3
TableName: 'Example',
4
Item: {
5
CounterName: 'Example1',
6
},
7
ConditionExpression: 'attribute_not_exists(CounterName)'
8
},
9
function (error, data) {
10
if (error) {
11
// If conflict, an error will be thrown
12
} else {
13
14
}
15
}
16
);
Copied!
When using ConditionExpression, and if there is a conflicting.
Sample error:
1
{
2
"message":"The conditional request failed",
3
"code":"ConditionalCheckFailedException",
4
"time":"2019-02-03T09:20:20.260Z",
5
"statusCode":400,
6
"retryable":false
7
}
Copied!

Query vs Scan

Query
Scan
The Query operation finds items based on primary key values. You can query any table or secondary index that has a composite primary key (a partition key and a sort key).
The Scan operation returns one or more items and item attributes by accessing every item in a table or a secondary index. To have DynamoDB return fewer items, you can provide a FilterExpression operation.

Indexes

Sorting is all done on the same partition.
Have to partition wisely.
Global Secondary Index
Local Secondary Index
An index with a partition key and a sort key that can be different from those on the base table.
An index that has the same partition key as the base table, but a different sort key.
A global secondary index has no size limitations and has its own provisioned throughput settings for read and write activity that are separate from those of the table.
As a result, the total size of indexed items for any one partition key value can't exceed 10 GB. Also, a local secondary index shares provisioned throughput settings for read and write activity with the table it is indexing.
Each table in DynamoDB is limited to 20 global secondary indexes (default limit)
Each table in DynamoDB is limited to 5 local secondary indexes.

Global Secondary Index

Reducing DynamoDB costs

    Look for batch fetch
    Look for batch writes
    Look for scans
    Look for large queries
    Check projections

Alternatives

Last modified 2yr ago