Chapter 5 — Databases
Day 1 — DynamoDB Tables and Keys
1. Concept Primer
DynamoDB is a NoSQL key-value/document store. Every table needs a partition key (determines which physical partition an item lives on) and optionally a sort key (orders items within a partition). Together they form the primary key.
2. Hands-on Exercise
Create a table with a composite key, insert a few items, and query by partition key.
3. Exact Commands
floci start && eval $(floci env)
aws dynamodb create-table \
--table-name Orders \
--attribute-definitions \
AttributeName=CustomerId,AttributeType=S \
AttributeName=OrderId,AttributeType=S \
--key-schema \
AttributeName=CustomerId,KeyType=HASH \
AttributeName=OrderId,KeyType=RANGE \
--billing-mode PAY_PER_REQUEST
aws dynamodb put-item --table-name Orders --item '{
"CustomerId": {"S": "cust-1"},
"OrderId": {"S": "order-100"},
"Total": {"N": "42.50"}
}'
aws dynamodb put-item --table-name Orders --item '{
"CustomerId": {"S": "cust-1"},
"OrderId": {"S": "order-101"},
"Total": {"N": "17.00"}
}'
aws dynamodb query --table-name Orders \
--key-condition-expression "CustomerId = :c" \
--expression-attribute-values '{":c":{"S":"cust-1"}}'
4. Gotchas
- DynamoDB is one of the best-supported services in Floci — full CRUD, queries, and streams behave close to real AWS.
PAY_PER_REQUESTbilling mode avoids having to specify (and think about) provisioned read/write capacity units while you're still learning the data model.
5. Self-Check
If you wanted to fetch a single specific order instead of all of a customer's orders,
would you use query or get-item — and what key(s) would you need?
Day 2 — Global Secondary Indexes and Streams
1. Concept Primer
A GSI lets you query by an attribute other than the primary key, at the cost of eventual consistency and extra storage. DynamoDB Streams capture an ordered, near real-time log of item-level changes — the mechanism that feeds Lambda triggers later.
2. Hands-on Exercise
Enable a stream on the Orders table and read change events after inserting an item.
3. Exact Commands
eval $(floci env)
aws dynamodb update-table --table-name Orders \
--stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES
STREAM_ARN=$(aws dynamodb describe-table --table-name Orders \
--query 'Table.LatestStreamArn' --output text)
echo "$STREAM_ARN"
aws dynamodb put-item --table-name Orders --item '{
"CustomerId": {"S": "cust-2"},
"OrderId": {"S": "order-200"},
"Total": {"N": "9.99"}
}'
SHARD_ID=$(aws dynamodbstreams describe-stream --stream-arn $STREAM_ARN \
--query 'StreamDescription.Shards[0].ShardId' --output text)
SHARD_ITERATOR=$(aws dynamodbstreams get-shard-iterator \
--stream-arn $STREAM_ARN --shard-id $SHARD_ID \
--shard-iterator-type TRIM_HORIZON --query 'ShardIterator' --output text)
aws dynamodbstreams get-records --shard-iterator $SHARD_ITERATOR
4. Gotchas
- Enabling a stream returns a
LatestStreamArnimmediately — save it, since the ARN changes if you disable and re-enable streaming later. - Reading a stream manually (as above) is only for understanding the mechanism; in practice you'll attach a Lambda as an event source mapping (Chapter 7) instead of polling shards by hand.
5. Self-Check
What does NEW_AND_OLD_IMAGES give you in a stream record that NEW_IMAGE alone
wouldn't?
Day 3 — RDS: Launching a Real Postgres Instance
1. Concept Primer
Unlike DynamoDB, RDS wraps an actual relational database engine. Floci runs a real Postgres/MySQL container behind the RDS API, so once the instance is "available," you're talking to genuine SQL — not a simulation of one.
2. Hands-on Exercise
Create a Postgres RDS instance, wait for it to become available, and connect with psql.
3. Exact Commands
eval $(floci env)
aws rds create-db-instance \
--db-instance-identifier day3-db \
--db-instance-class db.t3.micro \
--engine postgres \
--master-username floci_admin \
--master-user-password floci_password123 \
--allocated-storage 20
# Poll until status is "available"
aws rds describe-db-instances --db-instance-identifier day3-db \
--query 'DBInstances[0].DBInstanceStatus'
ENDPOINT=$(aws rds describe-db-instances --db-instance-identifier day3-db \
--query 'DBInstances[0].Endpoint.Address' --output text)
PORT=$(aws rds describe-db-instances --db-instance-identifier day3-db \
--query 'DBInstances[0].Endpoint.Port' --output text)
PGPASSWORD=floci_password123 psql -h $ENDPOINT -p $PORT -U floci_admin -d postgres -c "SELECT version();"
4. Gotchas
- Because this spins up a real container, it's slower to provision than S3/DynamoDB —
poll
describe-db-instancesrather than assuming it's instantly ready. - Master password rules that real AWS enforces (length/complexity) may be loosely checked locally — don't take a locally-accepted password as proof it'd pass real AWS validation.
- Requires Docker to be running, since Postgres/MySQL are real containers under the hood.
5. Self-Check
What's the practical difference in confidence between testing SQL logic against Floci's RDS versus testing DynamoDB queries — and why does that difference exist?