The simplest NoSQL model: a giant distributed hash table. Learn key-value operations with Redis and DynamoDB, TTLs, and the access patterns — caching, sessions, counters — they excel at.
A key-value store maps a unique key to an opaque value with O(1) get and put, and nothing else — no querying inside the value, no joins. That radical simplicity is exactly why it scales to enormous throughput and low latency. You reach for it when you know the key and want the value as fast as physically possible: a cache, a session, a counter.
# Redis — the canonical key-value store, via redis-cli
SET user:1001:name "Ann" # put
GET user:1001:name # get -> "Ann"
DEL user:1001:name # delete
EXISTS user:1001:name # 0/1
# the ONLY access path is the key. You can't query "all users named Ann".
# That constraint is what makes it O(1) and massively scalable.Key-value stores shine as caches because they support per-key expiry (TTL) and memory-bounded eviction. Set a value to expire in 60 seconds and it self-cleans; configure an eviction policy and the store drops least-recently-used keys under memory pressure. This is the mechanism behind the cache-aside pattern covered in depth by the Caching course.
SET session:abc123 "{...}" EX 3600 # expires in 3600s (1 hour)
TTL session:abc123 # seconds left
INCR page:home:views # atomic counter (great for metrics)
EXPIRE page:home:views 86400 # roll the counter daily
# memory-bounded: configure maxmemory + an eviction policy
# maxmemory-policy allkeys-lru -> drop least-recently-used under pressure
# -> a self-managing cache. See the Caching course for cache-aside patterns.Some key-value stores (Redis especially) go beyond opaque blobs, offering typed values — lists, sets, sorted sets, hashes — with atomic operations. This turns the store into a Swiss-army tool for leaderboards (sorted sets), queues (lists), rate limiters, and deduplication (sets), all at in-memory speed. Knowing these structures lets you solve real problems without a heavier system.
# Redis data structures, each with atomic ops:
HSET user:1001 name "Ann" plan "pro" # hash: a small record under one key
LPUSH queue:jobs "job-42" # list: a simple queue
SADD tags:post:9 "sql" "nosql" # set: unique membership
ZADD leaderboard 4200 "ann" # sorted set: score-ranked
ZREVRANGE leaderboard 0 9 WITHSCORES # top-10 leaderboard in one call
# these turn a KV store into leaderboards, queues, rate limiters, dedup —
# at in-memory speed.Cloud key-value stores like DynamoDB add durability, replication, and elastic scale to the model. The design discipline is the same: you pick a partition key that spreads load evenly and design keys around your access patterns. Get the key design right and it delivers single-digit-millisecond reads at any scale; get it wrong (a hot partition) and it throttles.
import boto3
table = boto3.resource("dynamodb").Table("Sessions")
# put + get by key — the partition key spreads data across nodes
table.put_item(Item={"session_id": "abc123", "user_id": 1001, "cart": []})
item = table.get_item(Key={"session_id": "abc123"})["Item"]
# design rule: pick a partition key with HIGH cardinality + even access.
# good: session_id (spreads evenly)
# bad: "status" with 3 values -> a few hot partitions -> throttling
# key design = performance. Model keys around your reads.