Redis · lesson 4 of 14
Beginner
4Intermediate
7- 5 MULTI/EXEC Transactions and the WATCH-Based Optimistic Lock
- 6 Pub/Sub: Channels, Patterns, and the Message That Never Arrives
- 7 RDB vs AOF: What Survives a Hard Kill and What Doesn't
- 8 Replication: A Read-Only Replica, and What WAIT Actually Guarantees
- 9 ACL: a User Restricted to One Key Pattern and One Command
- 12 maxmemory and Eviction: What Redis Throws Away When It's Full
- 13 Cache-Aside with Redis: Stale Reads, Races and Stampedes
Advanced
3Also part of Redis
3Sorted Sets: Building a Leaderboard, and the Ascending-Order Trap
ZRANGE returns lowest score first by default — a real surprise the first time you build a leaderboard and see the worst player listed first. ZREVRANGE, ZRANK, and range queries fix it.
By SkillByExample · Published
A sorted set keeps every member ranked by a score automatically — the surprise is which direction “ranked” means by default.
Building a leaderboard
docker exec redis-lesson redis-cli ZADD leaderboard 100 alice 250 bob 175 carol
docker exec redis-lesson redis-cli ZRANGE leaderboard 0 -1 WITHSCORES
3
alice
100
carol
175
bob
250
ZADD returns 3 — three new members added. ZRANGE ... WITHSCORES lists everyone… in
ascending order. Alice has the lowest score and is listed first — for a feature literally
called a leaderboard, that’s backwards from what most people expect on first read.
The fix: ZREVRANGE for highest-first
docker exec redis-lesson redis-cli ZREVRANGE leaderboard 0 -1 WITHSCORES
bob
250
carol
175
alice
100
Same data, reverse order — ZREVRANGE is the one an actual leaderboard display wants.
ZRANGE isn’t wrong or buggy; it’s documented to be ascending. The mistake is assuming
“sorted set” implies “highest first” without checking.
Rank: two directions, same trap
docker exec redis-lesson redis-cli ZRANK leaderboard alice
docker exec redis-lesson redis-cli ZREVRANK leaderboard alice
0
2
ZRANK counts from the bottom — alice, the lowest score, is rank 0. ZREVRANK counts from
the top — alice is in last place, rank 2 (of 3, zero-indexed). “What place is alice in” on a
leaderboard means ZREVRANK, not ZRANK.
Atomic score updates
docker exec redis-lesson redis-cli ZINCRBY leaderboard 200 alice
docker exec redis-lesson redis-cli ZSCORE leaderboard alice
300
300
ZINCRBY adds to a score atomically and returns the new total — alice jumps from 100 to 300
in one round trip, safe even with concurrent scorers.
Range queries by score
docker exec redis-lesson redis-cli ZRANGEBYSCORE leaderboard 150 300
carol
bob
alice
“Everyone between 150 and 300 points” — carol (175), bob (250), and now alice (300, after the
increment above) all qualify, returned in ascending score order same as plain ZRANGE.
Practice
1. Remove and return the highest-scoring member in one atomic operation.
docker exec redis-lesson redis-cli ZADD leaderboard 100 alice 250 bob 175 carol
docker exec redis-lesson redis-cli ZPOPMAX leaderboard
3
bob
250
ZPOPMAX reads and removes the top scorer atomically — useful for “process the current
leader, then let someone else take the top spot” workflows without a separate read-then-delete
race condition.
2. Query an exclusive range — strictly more than a given score.
docker exec redis-lesson redis-cli ZRANGEBYSCORE leaderboard "(100" 300
carol
Wrapping the lower bound in parentheses makes it exclusive — a plain 100 would include a
member at exactly 100, "(100" excludes it. (bob was already popped in the previous task,
so only carol at 175 remains in range.)
3. Get the total number of members without listing them.
docker exec redis-lesson redis-cli ZCARD leaderboard
2
ZCARD is O(1) — it reads a stored count rather than counting members on demand, so it stays
fast regardless of how large the sorted set is.
Next: transactions — MULTI, EXEC, and the WATCH-based optimistic lock that can abort mid-flight.