iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Sets

Redis sets are unordered collections of unique strings. SADD / SREM / SISMEMBER are O(1); union / intersect / diff are atomic, fast, and the foundation of tag systems, dedup, and follower graphs.

SADD, intersections, unions, real recipes

EXAMPLE
# 1) Basic operations
SADD tags red blue green       # add 3 members; returns 3 added
SADD tags red                  # returns 0 (already there)
SCARD tags                     # count
SISMEMBER tags blue            # 1 (member) / 0 (not)
SMISMEMBER tags blue purple     # batch check
SREM tags red                  # remove
SMEMBERS tags                  # all members
SRANDMEMBER tags               # random member
SRANDMEMBER tags 3              # 3 random distinct
SPOP tags                      # pop random member (removes it)

# 2) Set arithmetic
SADD a 1 2 3 4
SADD b 3 4 5 6

SINTER a b                     # intersection: 3 4
SUNION a b                     # union: 1 2 3 4 5 6
SDIFF a b                      # in a not in b: 1 2

# Store the result
SINTERSTORE common a b         # → common = {3, 4}
SUNIONSTORE all a b            # → all    = {1..6}
SDIFFSTORE only_a a b          # → only_a = {1, 2}

# 3) Scan to iterate without blocking (large sets)
SSCAN tags 0 MATCH * COUNT 100

# === Real recipes ===

# 4) Unique visitor count per day (cheaper than COUNT(DISTINCT) in DB)
SADD visitors:2026-06-08 user_42
SADD visitors:2026-06-08 user_99
SCARD visitors:2026-06-08              # unique visitors today

# 7-day unique visitors (union of 7 daily sets)
SUNIONSTORE visitors:last7 visitors:2026-06-02 visitors:2026-06-03 ... visitors:2026-06-08
SCARD visitors:last7
# (For massive cardinalities, use HyperLogLog — PFADD / PFCOUNT)

# 5) Tag system — bidirectional
SADD post:42:tags python redis backend
SADD tag:python:posts 42 51 67
SADD tag:redis:posts  42 18 91

# Posts tagged with BOTH python AND redis:
SINTER tag:python:posts tag:redis:posts

# Posts tagged with python OR redis:
SUNION tag:python:posts tag:redis:posts

# 6) Social — follower / following graph
SADD user:42:following user:99 user:51
SADD user:99:followers user:42
SADD user:51:followers user:42

# 'People you may know' = friends of friends, minus already-following
SINTER user:42:following user:99:following     # users you both follow
SDIFF  user:99:following user:42:following user:42      # who 99 follows that you don't

# 7) Online users / presence
SADD online:room:42 user:99
SADD online:room:42 user:51
EXPIRE online:room:42 30                       # auto-cleanup after 30s

# Active rooms
SCARD online:room:42

# 8) Permission / role system
SADD role:admin:perms can_delete can_ban can_edit
SADD role:editor:perms can_edit

# Does this user have permission?
SADD user:42:perms can_edit
SISMEMBER user:42:perms can_delete    # 0 — no

# 9) Rate limit lists (allowlist / denylist)
SADD allowed_ips 10.0.0.5 10.0.0.7
SADD blocked_ips 203.0.113.42
SISMEMBER blocked_ips $client_ip

# 10) Job dedup
# Before queuing a job, check if it's already queued:
SISMEMBER queued_jobs job:hash:abc
# If not, add to set + push to a list
SADD queued_jobs job:hash:abc
LPUSH queue:jobs job:abc
# After processing, SREM the job hash.

# 11) Node + ioredis
import Redis from 'ioredis';
const redis = new Redis();

await redis.sadd('visitors:today', userId);
const unique = await redis.scard('visitors:today');

const tagged = await redis.sinter('tag:python:posts', 'tag:redis:posts');

# Conditional follow (atomic — only add if not already present, return delta)
const added = await redis.sadd(`user:${a}:following`, b);
if (added) {
    await redis.sadd(`user:${b}:followers`, a);
    await bus.publish('follow', { a, b });
}

# 12) Performance
# - SADD / SREM / SISMEMBER are O(1)
# - SINTER is O(N*M) where N is smallest set, M is number of sets — keep small sets first
# - SMEMBERS is O(N) — avoid on huge sets; use SSCAN
# - Use SPOP for unique sampling without replacement

# 13) Set vs sorted set vs hash
# Set         : unique members, no order, set arithmetic
# Sorted set  : unique members WITH a score (leaderboards, time windows)
# Hash        : key → value within one Redis key (object field updates)
# List        : ordered, allows duplicates (queues, recent-N)

# 14) Use cases at a glance
#   Unique counts (low cardinality) — Set + SCARD
#   Unique counts (huge cardinality) — HyperLogLog (PFADD / PFCOUNT)
#   Tag systems / many-to-many — Sets on both sides
#   Followers / friends-of-friends — Set intersection / difference
#   Online users with TTL — Set + EXPIRE on the key
#   Permissions — Set + SISMEMBER

# 15) Common pitfalls
#   • SMEMBERS on a million-element set blocks Redis — use SSCAN
#   • Forgetting EXPIRE — sets grow forever
#   • Storing big JSON blobs as set members — keep members as IDs

Why it matters

Sets turn set theory into one-line Redis operations — tag systems, mutual-followers, online users, unique daily visitors. For massive cardinalities (millions of unique IPs), switch to HyperLogLog and trade ~0.8% error for kilobytes of memory.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
SADD tags "sql" "postgres" "redis"
SMEMBERS tags
SISMEMBER tags "sql"  # 1
SINTER tagsA tagsB    # intersection
Try it Yourself »

Discussion

Loading…