Skip to content

3. Data Types in Depth

Redis data structures are like a toolbox: each type is designed to solve a specific kind of problem. Let's walk through them one by one.

3.1 String: The Basic Building Block

Analogy: A String is like a drawer. The key is the label, and the value is whatever you put inside. It is simple, direct, and extremely versatile.

Use cases: caching, counters, distributed locks, serialized objects

bash
# Set and get
SET user:1:name "Alice"
GET user:1:name
bash
"Alice"
bash
# Counter: article views
SET article:1001:views 0
INCR article:1001:views
INCR article:1001:views
INCRBY article:1001:views 5
GET article:1001:views
bash
"7"
bash
# Set an expiration time in seconds
SET captcha:abc123 "8392" EX 300
TTL captcha:abc123
bash
(integer) 297
bash
# Distributed lock: NX means set only when the key does not exist
SET lock:order:1001 "owner_001" NX EX 10
bash
OK

3.2 List: A Simple Message Queue

Analogy: A List is like a conveyor belt. Push from the left (LPUSH) and pop from the right (RPOP) to implement first-in, first-out processing.

Use cases: message queues, recent activity lists, task queues, timelines

bash
# Simulate a message queue: producer
LPUSH queue:email "user1@example.com|welcome"
LPUSH queue:email "user2@example.com|password reset"

# Check queue length
LLEN queue:email

# Consumer: pop from the right
RPOP queue:email
bash
(integer) 2
"user1@example.com|welcome"
bash
# Blocking pop: wait up to 5 seconds if there is no message
BRPOP queue:email 5

# Read a list range (pagination)
LPUSH timeline:uid1001 "post A" "post B" "post C"
LRANGE timeline:uid1001 0 9
bash
1) "post C"
2) "post B"
3) "post A"

3.3 Hash: A Natural Container for Objects

Analogy: A Hash is like a folder. The outer label is the key, and inside are field-value cards that store each piece of information.

Use cases: user profiles, product details, configuration items

bash
# Store user information
HSET user:1001 name "Bob" age 28 email "bob@example.com" vip 1

# Get one field
HGET user:1001 name

# Get all fields
HGETALL user:1001

# Check whether a field exists
HEXISTS user:1001 phone

# Atomically increment a field
HINCRBY user:1001 age 1
bash
"Bob"
1) "name"
2) "Bob"
3) "age"
4) "28"
5) "email"
6) "bob@example.com"
7) "vip"
8) "1"
(integer) 0
(integer) 29

Tip: When a Hash has fewer than 128 fields and each value is smaller than 64 bytes, Redis can use a compact encoding with very low memory overhead. That makes Hash a great choice for user profile data.

3.4 Set: A Box of Unique Tags

Analogy: A Set is like a box of unique labels. Each element appears at most once, and membership checks are fast.

Use cases: tag systems, mutual friends, deduplication, lotteries

bash
# Add tags to articles
SADD article:1001:tags "Redis" "database" "cache" "backend"
SADD article:1002:tags "Redis" "NoSQL" "performance"

# Get all tags
SMEMBERS article:1001:tags

# Intersection: shared tags
SINTER article:1001:tags article:1002:tags

# Union: all tags
SUNION article:1001:tags article:1002:tags

# Difference: tags article 1 has but article 2 does not
SDIFF article:1001:tags article:1002:tags

# Random lottery: pick 2 winning users
SADD lottery:2024 "user1" "user2" "user3" "user4" "user5"
SRANDMEMBER lottery:2024 2
bash
1) "Redis"
2) "database"
3) "cache"
4) "backend"
1) "Redis"
1) "Redis"
2) "database"
3) "cache"
4) "backend"
5) "NoSQL"
6) "performance"
1) "database"
2) "cache"
3) "backend"
1) "user3"
2) "user1"

3.5 Sorted Set: An Auto-Sorted Leaderboard

Analogy: A Sorted Set is like a live scoreboard. Each member has a score, and Redis keeps the ranking sorted for you.

Use cases: leaderboards, delayed queues, priority tasks, range queries

bash
# Game leaderboard: ZADD key score member
ZADD leaderboard 1500 "playerA"
ZADD leaderboard 2300 "playerB"
ZADD leaderboard 1800 "playerC"
ZADD leaderboard 3100 "playerD"
ZADD leaderboard 900  "playerE"

# Sort by score from high to low (top 3)
ZREVRANGE leaderboard 0 2 WITHSCORES

# Check a player's rank (starts from 0)
ZREVRANK leaderboard "playerA"

# Increase a player's score
ZINCRBY leaderboard 500 "playerA"

# Query players with scores between 1000 and 3000
ZRANGEBYSCORE leaderboard 1000 3000 WITHSCORES
bash
1) "playerD"
2) "3100"
3) "playerB"
4) "2300"
5) "playerC"
6) "1800"
(integer) 3
"2000"
1) "playerC"
2) "1800"
3) "playerB"
4) "2300"
5) "playerA"
6) "2000"
7) "playerD"
8) "3100"

3.6 Bitmap: A Space-Efficient Switch Panel

Analogy: A Bitmap is like a row of light switches. Each position is either on or off. Tracking daily sign-ins for 100 million users can take only about 12 MB.

Use cases: user sign-ins, online status, feature flags, Bloom filters

bash
# User 1001 signed in on day 1
SETBIT sign:1001:202401 0 1

# User 1001 signed in on day 5
SETBIT sign:1001:202401 4 1

# User 1001 signed in on day 31
SETBIT sign:1001:202401 30 1

# Check whether day 5 was signed in
GETBIT sign:1001:202401 4

# Count sign-in days this month
BITCOUNT sign:1001:202401

# Check whether day 3 was signed in
GETBIT sign:1001:202401 2
bash
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 3
(integer) 0

3.7 HyperLogLog: A Tiny Distinct Counter

Analogy: HyperLogLog is like an estimator that does not need to remember every element, yet can count distinct values with tiny fixed memory usage, about 12 KB per key.

Use cases: unique visitors, daily active users, cardinality estimation

bash
# Count website UVs (unique visitors)
PFADD uv:20240101 "user_001" "user_002" "user_003"
PFADD uv:20240101 "user_004" "user_002" "user_005"
PFADD uv:20240101 "user_001" "user_006"

# Return the deduplicated count (about 0.81% standard error)
PFCOUNT uv:20240101

# Merge UV statistics across multiple days
PFADD uv:20240102 "user_007" "user_008" "user_002"
PFMERGE uv:202401_all uv:20240101 uv:20240102
PFCOUNT uv:202401_all
bash
(integer) 1
(integer) 1
(integer) 1
(integer) 6
OK
(integer) 8

Note: HyperLogLog is a probabilistic algorithm, so the result is approximate. It is a good fit for huge datasets where a tiny error is acceptable. Use Set when you need exact counts.

3.8 Stream: A Modern Message Queue

Analogy: Stream is like a radio station with an archive. New listeners can replay historical messages through consumer groups, so they do not miss events.

Use cases: message queues, event sourcing, log collection

bash
# Producer: add messages to a Stream
XADD mystream * user "Alice" action "login" ip "192.168.1.100"
XADD mystream * user "Bob" action "purchase" amount "299"
XADD mystream * user "Charlie" action "logout"
bash
"1704067200000-0"
"1704067200100-1"
"1704067200200-2"
bash
# Consumer: read messages
XRANGE mystream - +

# Read the latest 2 entries
XREVRANGE mystream + - COUNT 2

# Create a consumer group
XGROUP CREATE mystream mygroup $ MKSTREAM

# Consume through the group (each message is delivered to one consumer)
XREADGROUP GROUP mygroup consumer1 COUNT 1 BLOCK 5000 STREAMS mystream >

# Acknowledge that the message has been processed
XACK mystream mygroup 1704067200000-0
bash
1) 1) "1704067200000-0"
   2) 1) "user"
      2) "Alice"
      3) "action"
      4) "login"
      5) "ip"
      6) "192.168.1.100"
2) 1) "1704067200100-1"
   2) 1) "user"
      2) "Bob"
      3) "action"
      4) "purchase"
      5) "amount"
      6) "299"
3) 1) "1704067200200-2"
   2) 1) "user"
      2) "Charlie"
      3) "action"
      4) "logout"
OK
1) 1) "mystream"
   2) 1) 1) "1704067200100-1"
         2) 1) "user"
            2) "Bob"
            3) "action"
            4) "purchase"
            5) "amount"
            6) "299"
(integer) 1

Data Type Selection Cheat Sheet

RequirementRecommended TypeExample
Simple cacheStringCached user token
Object storageHashUser profile
Message queueStream / ListOrder processing queue
LeaderboardSorted SetProduct sales ranking
Deduplicated collectionSetArticle tags
Massive distinct countingHyperLogLogWebsite UV
Bit operationsBitmapDaily sign-in
Time series style eventsStreamLog collection