Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Work with multiple keys

Work with multiple keys in Redis — practical steps, troubleshooting, and what to learn next.

Focus: work with multiple keys

Sponsored

You've mastered setting, getting, and deleting values one at a time. But what happens when your app needs to batch-check cache freshness, clear temporary sessions, or atomically move data between keys? Doing these one-by-one is slow, error-prone, and wastes roundtrips. Redis provides powerful multi-key commands that let you read, write, and delete many keys in a single call — cutting latency and keeping your logic clean.

The problem this lesson solves

Real applications rarely touch a single key in isolation. A typical session store might need to check the TTL of all active sessions, or a leaderboard might need to retrieve scores for the top 10 players. Without multi-key operations, you'd write a loop of GET or SET commands — each one a separate network roundtrip. This multiplies latency, increases connection overhead, and makes your code harder to read.

Multi-key commands solve this by bundling multiple operations into one atomic or pipeline-friendly call. They reduce network chatter, improve performance, and often provide atomicity guarantees that loops cannot.

Core concept / mental model

Think of Redis as a giant key-value dictionary on a remote server. Each single-key command is like asking a friend to fetch one item from a shelf. Multi-key commands are like handing your friend a list of items and letting them grab everything in one trip.

Definitions

  • Multi-key commands: Redis operations that accept multiple key arguments in a single command (e.g., MGET, MSET, DEL, EXISTS).
  • Atomicity: A multi-key command either completes fully or not at all — no partial updates when using MSET, for example.
  • Pipeline vs multi-key: Pipelining sends several commands together but doesn't guarantee atomicity; multi-key commands are inherently atomic for that single operation.

Pro tip: Multi-key commands are not available in Redis Cluster unless all keys hash to the same slot (same hash tag). For most single-instance or stand-alone Redis setups, they work perfectly.

How it works step by step

Let's walk through the core multi-key commands and how they behave.

1. MGET — Get multiple values in one call

Provide two or more keys, and Redis returns an array of values (nil for missing keys).

2. MSET — Set multiple key-value pairs atomically

All keys are written together; no partial success.

3. DEL — Delete multiple keys at once

Works the same as single-key DEL, but accepts a list.

4. EXISTS — Check existence of multiple keys

Returns the count of keys that exist.

5. KEYS vs SCAN — Pattern-based retrieval

  • KEYS pattern returns all matching keys in one shot (blocking on large datasets).
  • SCAN cursor [MATCH pattern] [COUNT count] iterates incrementally, non-blocking — preferred for production.

Command syntax examples

# Atomic set of two keys
MSET user:101:name Alice user:101:role admin

# Get both values
MGET user:101:name user:101:role
# Returns: 1) "Alice", 2) "admin"

# Check existence of three keys
EXISTS user:101:name user:101:role user:999:none
# Returns: 2

# Delete two keys
DEL user:101:name user:101:role
# Returns: 2

Hands-on walkthrough

Let's build a practical example using Python's redis library. We'll simulate a user session store with multiple keys.

Setup

import redis

r = redis.Redis(host='localhost', port=6379, decode_responses=True)
r.flushdb()  # clean slate

Example 1: Bulk insert with MSET

# Set three session keys for a user
r.mset({
    "session:101:token": "abc123",
    "session:101:expires": "2025-12-31",
    "session:101:role": "editor"
})
print("MSET done")

Output:

MSET done

Example 2: Bulk read with MGET

keys = ["session:101:token", "session:101:expires", "session:101:role", "session:999:token"]
values = r.mget(keys)
print("Values:", values)

Output:

Values: ['abc123', '2025-12-31', 'editor', None]

Note: missing key session:999:token returns None.

Example 3: Check existence and delete multiple keys

to_check = ["session:101:token", "session:101:expires", "session:999:token"]
count = r.exists(*to_check)
print(f"Exist count: {count}")

# Delete first two
r.delete("session:101:token", "session:101:expires")
print(f"Remaining after delete: {r.exists('session:101:token', 'session:101:expires')}")

Output:

Exist count: 2
Remaining after delete: 0

Example 4: Using SCAN to find keys by pattern

# Add a few more keys
r.set("cache:homepage", "cached_html")
r.set("cache:about", "cached_about")
r.set("temp:123", "temporary")

# Non-blocking SCAN
cursor = 0
pattern = "cache:*"
found = []
while True:
    cursor, keys = r.scan(cursor=cursor, match=pattern, count=10)
    found.extend(keys)
    if cursor == 0:
        break
print(f"Keys matching 'cache:*': {found}")

Output:

Keys matching 'cache:*': ['cache:homepage', 'cache:about']

Compare options / when to choose what

Command Use case Atomic? Blocking?
MGET / MSET Bulk read/write of known keys Yes No
DEL Delete multiple keys Yes No
EXISTS Check many keys for presence Yes No
KEYS pattern List all keys matching a pattern (dev only) No Yes (blocking)
SCAN Iterate keys matching a pattern (production) No No (non-blocking)

When to choose what:

  • Use MGET/MSET when you know the exact keys and need atomic operations.
  • Use EXISTS with multiple keys to batch-check presence.
  • Use DEL to cleanup in bulk.
  • Use SCAN for pattern-based iteration in production; avoid KEYS entirely on large datasets.

Troubleshooting & edge cases

Error: "MOVED" redirect in Cluster mode

If you're using Redis Cluster and keys hash to different slots, MGET and MSET will fail with a MOVED error. Solution: Use hash tags ({user:101}:token) to keep related keys in the same slot, or switch to a pipeline with per-slot grouping.

Memory: KEYS freezes Redis

KEYS * on a database with 10 million keys can block the server for seconds. Always prefer SCAN. If you must use KEYS, never run it in production.

Partial failures: MSET truly atomic

MSET is all-or-nothing. If one key fails (e.g., due to memory), none are written. MSETNX (set-if-not-exists) is also atomic but only succeeds if all keys are absent.

Missing keys return None (or nil)

MGET returns None for missing keys — not an error. Check for None in your application logic.

What you've learned & what's next

You can now:

  • Use MGET and MSET to read/write multiple keys atomically.
  • Use EXISTS and DEL with multiple arguments to check and delete batches.
  • Differentiate between KEYS (blocking, dev only) and SCAN (non-blocking, production-safe).
  • Handle edge cases like Cluster mode and large datasets.

Next up: Expire and TTL — learn how to set keys that automatically expire, and how to check remaining time-to-live. Perfect for cache invalidation and session cleanup.

Practice recap

Try this mini-exercise: write a Python script that uses MSET to store 3 configuration keys (theme, language, timeout) for a user. Then use MGET to read them back, print each, and delete two of them with DEL. Observe how EXISTS reflects the change.

Common mistakes

  • Using KEYS * in production — blocks Redis and can crash a server with millions of keys. Use SCAN instead.
  • Assuming MGET/MSET work in Redis Cluster without hash tags — keys must belong to the same slot or you'll get MOVED errors.
  • Not checking for None in MGET results — missing keys return None, not an exception.
  • Using DEL without verifying existence — safe but wasteful; if you need to check, use EXISTS first or pipeline.

Variations

  1. Using pipelines to batch multiple single-key commands when atomicity is not required but roundtrips matter.
  2. Using hash tags {...} in Redis Cluster to force related keys into the same slot for multi-key operation support.
  3. Using MSETNX to set multiple keys only if none of them exist — atomic conditional set.

Real-world use cases

  • Session store: bulk read/write session attributes (token, expiry, role) for a user in one roundtrip.
  • Cache warmup: preload a dozen frequently accessed values into Redis atomically after a deployment.
  • Cleanup cron job: batch delete all expired temporary keys matching a pattern using SCAN + DEL.

Key takeaways

  • MGET and MSET let you read/write multiple keys atomically in one command — cutting network overhead.
  • EXISTS with multiple keys returns the count of existing keys; DEL deletes multiple keys at once.
  • KEYS is blocking and dangerous for production — always use SCAN for pattern iteration.
  • Redis Cluster restricts multi-key commands to keys in the same slot; use hash tags to work around this.
  • Missing keys in MGET return None — always handle None in application code.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.