Redis commands, exam-style

After this lesson you will turn any Redis sentence of the exam — a value with a lifetime, a list, a set, a ranking, an object — into the right structure and the exact commands, and say what Redis replies to each one.

The exam of 13 June 2025 followed concerts, and its Redis exercise started from the entity Instrument. First: "Create a set of instruments including "Keyboard", "Violin", and "Drums"". Then, for one point: "Perform an operation to add "Flute" to the set, with time to live equal to 10".

The obvious answer takes two commands, and Redis accepts both: SADD instruments "Flute", then EXPIRE instruments 10. Eleven seconds later someone runs SISMEMBER instruments "Keyboard".

Does Redis answer 1 or 0? Write your guess down. The last section settles it, and shows how to word a safe answer.

Strings, keys and the counter that cannot lose

Every Redis command names a key and says what to do with the value stored under it. The simplest value is a string: a piece of text or a number. The session stores one with SET and reads it with GET; for reading, "The only requirement is that we need to know the key_name" (p. 1582). The lecture runs the pair on the key foo (p. 355):

redis> SET foo "hello!"
OK
redis> GET foo
"hello!"

Read it as a conversation. SET answers OK and silently replaces whatever the key held; GET answers the value in quotes, or (nil) when there is no such key. A key or a value with spaces goes in double quotes: the exam of 24 June 2024 wants a key named "Line #0001" with the value "A long time ago in a galaxy far, far away". The slides print typographic quotes (“hello!“); type straight ones.

Four commands work on a whole key, whatever its type (p. 356, pp. 1583–1584). EXISTS "returns a value of 1 if the field exists, 0 otherwise"; DEL removes the key and answers how many keys it removed; TYPE names the structure under the key; RENAME moves the value to a new name.

redis> EXISTS foo
(integer) 1
redis> TYPE foo
string
redis> RENAME foo greeting
OK
redis> GET greeting
"hello!"
redis> DEL greeting
(integer) 1
redis> EXISTS greeting
(integer) 0
redis> GET greeting
(nil)

The lecture adds four helpers (p. 355). MSET and MGET write and read several keys in one round trip, STRLEN gives the length, and GETSET stores a new value and hands back the old one. The slide leaves out the reply of GETSET: it is the old value, "hello!".

redis> MSET foo "hello!" bar 1223
OK
redis> MGET foo bar
1) "hello!"
2) "1223"
redis> STRLEN foo
(integer) 6
redis> GETSET foo "bye!"
"hello!"

Look at "1223": it comes back in quotes. Redis keeps every number as a string and reads it as an integer only when a command needs one.

Counting, and the update that gets lost

Strings that hold integers can count. The session lists four commands (p. 1585): "INCR – Increases the value by 1", "DECR – Decreases the value by 1", "INCRBY – Increases the value by the amount set", "DECRBY – Decreases the value by the amount set". A missing key counts as 0, so the first INCR of a new counter answers 1; a value that is not an integer, like the "bye!" now in foo, gets an error:

redis> INCR visits
(integer) 1
redis> DECR visits
(integer) 0
redis> DECRBY visits 5
(integer) -5
redis> INCR foo
(error) ERR value is not an integer or out of range

The lecture's example (p. 355) adds a thousand in one step:

redis> SET bar 223
OK
redis> INCRBY bar 1000
(integer) 1223

Then the session asks a fair question. A client could add one with the commands it already has (p. 1586):

> x = GET key_name
  x = x + 1
  SET key_name x

"The proposed script is a general way of executing the increasing or decreasing operations. Then, why do we need them?" The answer is an animation (pp. 1588–1593). Two clients both GET 10, both compute 11 on their own side, both SET 11. Two increments were asked for, the counter moved by one, and the slide ends in red: "Using the script will cause these two increases to be applied incorrectly!" This is the lost update.

Atomic operation — an operation that runs as one indivisible step: no other client's command can run between its read and its write. In the session's words, "ATOMIC OPERATIONS are not affected by problems in case of concurrent access" (p. 1587).

Why is INCR atomic when the three lines are not? The three lines are three trips: a read, a sum on the client, a write. Between the read and the write lies a gap, and another client's read or write can fall into it. INCR does the read, the +1 and the write inside the server, in one command — and the server runs one command at a time. The lecture says it in two lines (p. 352): "Redis is a single-threaded server", and "All operations are atomic (no two commands can run at the same time)". No lock is involved: while a command runs, nothing else runs.

An increment is safe only when its read and its write happen inside one command.

Two clients, one counter

The session's picture of pp. 1588–1593 as a sequence you can replay, with time running downwards. Choose what each client sends and in which order the steps reach Redis, then press Next. The middle lane is the counter stored in Redis, the side lanes the value each client holds; grey labels show the steps still to come.

  1. Keep GET, +1, SET and the slide's order. Before you step, predict the counter at the last step. Then step through: at which step is the loss already decided?
    What you should see

    11. The loss is decided at step 3, when client 2 reads 10 although client 1 is about to write 11: from then on both clients compute 11, and the two SET commands only make it visible. This is the one thing the widget is built to show: an increment is lost when another client's command falls between your GET and your SET.

  2. Try the other three orders. For each, predict 11 or 12 before stepping.
    What you should see

    Only "client 2 starts after client 1 has written" reaches 12. In the other three, one client reads between the other's read and write, so both start from 10. Even when client 2 finishes first ("reads and writes in client 1's gap"), client 1's late SET writes its stale 11 over client 2's 11.

  3. Switch to a single INCR and replay all four orders. What changes, and why can no order lose an increment now?
    What you should see

    Every order ends at 12. Each client's whole increment is one command, and Redis executes one command at a time ("no two commands can run at the same time", p. 352): there is no gap left between a read and a write for the other client to fall into. The order only decides who gets 11 back and who gets 12.

You know the same cure from SQL: UPDATE counters SET value = value + 1 lets the database do the sum instead of the client. One command gets the isolation that lesson 3 asked of a whole transaction.

"Redis scripts are not atomic." The session calls the three lines "(a sort of) scripting" (p. 1586), but they are three separate commands sent by a client, with the sum done by the client. Real Redis scripts — Lua code that runs inside the server, listed among Redis's advantages as "LUA scripting support" (p. 365) — execute atomically, like a single command (Redis documentation, background). Explain atomicity with the single-threaded server, not with the slide's word "script".

Keys with a lifetime

Redis often works as a cache, and a cache has to forget on its own: a session nobody uses, a page that went stale. So any key can carry a clock. The session calls such pairs "temporary key-value pairs" and gives two commands (p. 1594): "EXPIRE – Set the lifespan of a variable (in seconds)" and "TTL – Returns the remaining lifespan of a variable (in seconds)". On the lecture slide (p. 356):

redis> EXPIRE foo 10
(integer) 1
redis> TTL foo
(integer) 10

EXPIRE answers 1 when it armed the clock and 0 when the key does not exist. "PEXPIRE and PTTL achieves the same operations in milliseconds" (p. 1594) — fine enough to show the time you spent typing:

redis> PEXPIRE foo 60000
(integer) 1
redis> PTTL foo
(integer) 58904

When the clock reaches zero, Redis deletes the key exactly as DEL would: the whole key, whatever it holds.

TTL answers in three ways, and the exam's "check its lifespan" is about them (p. 1595): the remaining seconds; "-1 – The key will never expire"; "-2 – The key has already expired". Read -2 as "there is no such key": Redis gives the same answer for a key that expired, was deleted or never existed. The three answers are three states of a key, and a handful of commands move a key between them.

permanent key TTL k → -1 temporary key TTL k → n no such key TTL k → -2 EXPIRE k n PERSIST k or SET k v SET k v SET k v EX n n reaches 0 · DEL k DEL k
Fig. 1. What TTL answers depends only on the state of the key: -1 permanent, n seconds left, -2 no such key. A plain SET and PERSIST both take a temporary key back to permanent; DEL takes either kind of key to "no such key".

The first move is a shortcut: SET takes the lifetime as an option, so the value and the clock arrive in one command (p. 1595). It is the natural answer to "Create a key-value pair with "best_book", the value "La ragazza delle Arance", and TTL equal to 100" (exam of 21 January 2025):

redis> SET best_book "La ragazza delle Arance" EX 100
OK

The next sentence of the slide hides a trap: "whenever the key is SET, the TTL is reset". Reset means removed, not restarted. A plain SET replaces the value and throws the clock away, and the key becomes permanent:

redis> SET k "v" EX 100
OK
redis> SET k "w"
OK
redis> TTL k
(integer) -1

Commands that change a value in place — INCR, LPUSH, SADD, HSET — leave the clock alone, and RENAME takes it along to the new name (Redis documentation, background). The last move removes a clock on purpose: "The PERSIST operator can be used to solve such a problem. It permanently stores a temporary variable in the database" (p. 1596). It answers 1 when it removed a timeout and 0 when there was none:

redis> PERSIST best_book
(integer) 1
redis> TTL best_book
(integer) -1

"PERSIST writes the key to disk." It does not: it only removes the expiry. Saving the data on disk — snapshots and append-only files — is the subject of lesson 19. The exam's "make it permanently stored" (21 January 2025) means PERSIST.

Lists: two ends and inclusive indexes

A list is a sequence of strings in a fixed order, duplicates allowed. You build it from either end (p. 1597): "RPUSH – Puts one or more new elements at the end of the list" and "LPUSH – Puts one or more new elements at the beginning of the list". "If the key does not exist, it will be created. A key with an empty list will be automatically deleted." Both commands answer the length of the list after the push. Here is the lecture's list of jobs (p. 357), with the replies Redis really gives:

redis> RPUSH jobs "foo"
(integer) 1
redis> LPUSH jobs "bar"
(integer) 2
redis> LRANGE jobs 0 -1
1) "bar"
2) "foo"

With several values in one command, the two ends behave differently. RPUSH appends them one by one at the tail, so they keep the order you typed. LPUSH puts them one by one at the head, each in front of the previous one, so the order comes out reversed.

RPUSH l a b c (integer) 3 l a b c from head 0 1 2 from tail -3 -2 -1 typed order kept

RPUSH: each value joins at the tail

LPUSH l a b c (integer) 3 l c b a from head 0 1 2 from tail -3 -2 -1 order reversed

LPUSH: each value joins at the head

Fig. 2. The same three values, two orders. RPUSH appends each value at the tail, so a b c stays a b c; LPUSH puts each one in front of the previous, so the last value typed ends at index 0. Both reply 3, the new length.

That settles the exam of 24 June 2024, "create a new list of lines involving the lines "Hey you", "Watch out", and "Hello there"": with RPUSH the first line typed is the first line stored.

Reading a range

"The LRANGE operator can be used to retrieve a subset of values from a list" (p. 1598), written LRANGE key first_index last_index. Three rules decide what comes back. Indexes start at 0. A negative index counts from the end: -1 is the last element, -2 the one before it. And both ends are included — unlike a Python slice, where l[0:2] stops before index 2.

redis> RPUSH lines "Hey you" "Watch out" "Hello there"
(integer) 3
redis> LRANGE lines 0 2
1) "Hey you"
2) "Watch out"
3) "Hello there"
from the head 0 1 2 3 4 l a b c d e from the tail -5 -4 -3 -2 -1 LRANGE l 0 2 a b c LRANGE l 0 -1 a b c d e LRANGE l 0 -2 a b c d LRANGE l -3 -1 c d e
Fig. 3. Every element has two addresses, from the head (0, 1, …) and from the tail (-1, -2, …). LRANGE includes both ends: 0 2 gives three elements, 0 -1 the whole list, 0 -2 all but the last.

The slide puts the negative stop another way: "Negative numbers (e.g., -N) mean that the operator will return all values besides the last N-1 values (e.g., -2 means that we are collecting all the elements, besides the last one)". It is the same rule counted from the tail: in a list of L elements, a stop of -N is position L − N.

Taking elements out: queues and stacks

"LPOP – Removes the first item of the list and returns it", "RPOP – Removes the last item of the list and returns it", and LLEN gives the length (p. 1599). LINDEX key index reads one element without removing it (p. 357). Combine the ends and you get the two classic structures: RPUSH with LPOP is a queue, first in first out; LPUSH with LPOP is a stack, last in first out.

redis> RPUSH q "job1" "job2" "job3"
(integer) 3
redis> LINDEX q 1
"job2"
redis> LPOP q
"job1"
redis> RPOP q
"job3"
redis> LLEN q
(integer) 1

Two list commands are made for job queues (p. 357). RPOPLPUSH src dst pops the last element of one list and pushes it onto the head of another in one atomic step: the slide moves "foo" from jobs to proc, and at every moment the job sits in one of the two lists. BLPOP and BRPOP are blocking pops: on an empty list the client waits until an element arrives or the timeout runs out — the "Blocking queues" among the use cases of the lecture (p. 350). On the list jobs above, the reply names the list, because one command can watch several:

redis> BLPOP jobs 0
1) "jobs"
2) "bar"

Membership is where a list is weak. "Check whether the animal "Bob" is in a list of animals named "Farm"" (exam of 12 September 2025) has no list command on the slides: you read the whole list with LRANGE Farm 0 -1, or ask LPOS Farm "Bob" (Redis 6.0.6 and later, background), which answers the position or (nil). Both walk the list — the slide marks LINDEX and LRANGE O(N), in red. When the question is "is X in there?", the structure made for it is a set.

Sets, sorted sets and hashes

A set drops the order and the duplicates: "SETS are similar to lists, but they don't have a specific value order, and each value can only appear once per set. SETS are useful as it is very quick to test the existence of a value, which is not as easy when it comes to lists" (p. 1600). Its commands start with S. SADD and SREM add and remove members, SISMEMBER "Returns 1 if the value is part of the set, 0 otherwise", SMEMBERS "Returns all the members in the set" (p. 1601), and SCARD, which the slides do not show, counts them.

redis> SADD instruments "Keyboard" "Violin" "Drums"
(integer) 3
redis> SADD instruments "Violin"
(integer) 0
redis> SISMEMBER instruments "Flute"
(integer) 0
redis> SREM instruments "Drums" "Piano"
(integer) 1
redis> SCARD instruments
(integer) 2
redis> SMEMBERS instruments
1) "Keyboard"
2) "Violin"

Sets also combine. The lecture's example (p. 358) has users = {John, Peter} and admins = {Peter}:

redis> SADD admins "Peter"
(integer) 1
redis> SADD users "John" "Peter"
(integer) 2
users admins users admins users admins John Peter John Peter John Peter SINTER SUNION SDIFF Peter John, Peter John
Fig. 4. SINTER users admins, SUNION users admins and SDIFF users admins on the sets of p. 358: in both, in either, in the first and not in the second. The third one is not symmetric — SDIFF admins users is empty.
redis> SINTER users admins
1) "Peter"
redis> SUNION users admins
1) "John"
2) "Peter"
redis> SDIFF users admins
1) "John"

A set has no order, so Redis may list the members of a reply in any order — the slide got "Peter" first. "SUNION – Combines two or more sets into one set" (p. 1601) returns the union without storing it; SUNIONSTORE dest key1 key2 keeps it under a new key (background). SPOP removes and returns a random member (p. 358). The SINTER box of p. 358 is in the slide's text but hidden under another box on the rendered page; its example is the one above.

Sorted sets: a set with a score

"Since sets are not ordered, Redis introduced the concept of an ORDERED SET. In an ORDERED SET, each element of the set is assigned to a score that is used to define the order in the set" (p. 1602). The lecture slide calls it a sorted set (p. 358), and so do the Redis docs: two names, one structure. Members stay unique, as in a set; the score, a floating-point number, decides their place, lowest first, and equal scores go in alphabetical order.

redis> ZADD scores 100 "John"
(integer) 1
redis> ZADD scores 50 "Peter" 200 "Charles" 1000 "Mary"
(integer) 3

The score comes first, ZADD key score member, with as many pairs as you like, and the reply counts the new members. ZRANGE key start stop (p. 1602) reads by position in score order, with the inclusive, negative-friendly indexes of LRANGE; add WITHSCORES to see the scores, and REV (Redis 6.2 and later, background) to start from the highest.

redis> ZRANGE scores 0 -1 WITHSCORES
1) "Peter"
2) "50"
3) "John"
4) "100"
5) "Charles"
6) "200"
7) "Mary"
8) "1000"
redis> ZRANGE scores 0 0 REV
1) "Mary"
rank 0 rank 1 rank 2 rank 3 scores Peter John Charles Mary 50 100 200 1000 ZRANGEBYSCORE scores 200 +inf score grows
Fig. 5. A sorted set is kept in score order, so a member's rank is its position, counted from 0. A score range picks a contiguous run of members: 200 to +inf gives Charles and Mary.
redis> ZRANK scores "Mary"
(integer) 3
redis> ZRANGEBYSCORE scores 200 +inf WITHSCORES
1) "Charles"
2) "200"
3) "Mary"
4) "1000"
redis> ZINCRBY scores 10 "Mary"
"1010"
redis> ZREMRANGEBYSCORE scores 0 100
(integer) 2

Every sorted-set reply on p. 358 checks out. Ranks start at 0, so Mary, the highest of four, has rank 3. ZRANGEBYSCORE includes its bounds and accepts +inf. ZINCRBY answers the new score, as a string. The range 0–100 removes Peter (50) and John (100). This is the structure behind "Create a list to store all Department specialties, sorted by their foundation year. Then, query the list to get the older one" (exam of 30 January 2026): the year is the score, and the oldest is ZRANGE key 0 0. It is also how you would keep the best checkpoint of a training run: the validation loss as the score, and rank 0 is the model to keep.

Hashes: one object under one key

"HASHES are mappings between string fields and string values" (p. 1603): a small dictionary under one key, much like a Python dict. That makes a hash the home of one object and its attributes. The key carries the type and the id of the object — user:1 on p. 357 — and each attribute becomes a field:

redis> HSET user:1 name John
(integer) 1
redis> HMSET user:1 lastname Smith visits 1
OK
redis> HGET user:1 name
"John"
redis> HGETALL user:1
1) "name"
2) "John"
3) "lastname"
4) "Smith"
5) "visits"
6) "1"

HSET takes several field–value pairs in one command (p. 1603) and answers how many fields are new; the lecture's HMSET (p. 357) is the older spelling and still works. HGETALL answers one flat list: field, value, field, value. HINCRBY keeps a counter inside the object, atomic like INCR:

redis> HINCRBY user:1 visits 1
(integer) 2

A clock still belongs to the whole key. HSET has no EX option, so "a single key-value pair to store all the data of one Gas Heater, with a TTL of 100" (30 January 2026) takes two commands, HSET then EXPIRE. Type EX 100 at the end of an HSET and Redis raises no error: it stores a field called "EX" with the value "100", and the key never expires.

From the exam sentence to the commands

Five of the nine past papers have a Redis exercise, and the 2026/27 rules name Redis among the topics of the practical part. Each of the five starts from an entity of the paper's ER diagram, is worth 3 to 5 points in items of 1 or 2, and asks for the same two moves: recognise the structure in the wording, then write its commands. The table collects the phrases of all five.

The phrases of the five past papers, the structure each one asks for, and its commands.
The paper saysStructureCommands
"create a new key-value pair named … with the value …"stringSET k "v"
"… and TTL equal to 100", "… that will expire in 1000 seconds"string with a clockSET k "v" EX 100, or SET then EXPIRE k 100
"check its lifespan", "check the TTL"any keyTTL k: seconds left, -1 or -2
"make it permanently stored"any keyPERSIST k
"create a new list of lines involving …", "a list … with two animals"listRPUSH k "a" "b" "c"
"collect the first three lines in the list"listLRANGE k 0 2
"check whether … is in a list"list (a set does it better)LPOS k "x", or LRANGE k 0 -1
"create a set of … including …", "add … to the set"setSADD k "x" "y"
"check whether … is part of the set"setSISMEMBER k "x": 1 or 0
"add … to the set, with time to live equal to 10"set; the clock goes on the whole keySADD k "x", then EXPIRE k 10, and say that the whole set expires
"combine the two sets"setSUNION k1 k2
"sorted by their foundation year … get the older one"sorted setZADD k 1921 "x" …, then ZRANGE k 0 0
"a single key-value pair to store all the data of one …"hashHSET k f1 v1 f2 v2 …, then EXPIRE

Two habits help beyond the commands. Name the keys after the entity of the diagram, and quote anything with a space. And when a sentence asks for something Redis cannot do word for word, write the closest commands and add one sentence on what Redis does instead: the readme of the past papers warns that "Exams might include minor typos" and asks you to "consider all the necessary assumptions to solve the exercise".

What each command costs

Next to every command the slides print its cost. The lecture sums it up as "It executes most commands in O(1) complexity" (p. 352); the table sorts the commands of pp. 355–358 by the cost printed beside them.

The costs printed on the command slides (pp. 355–358).
Printed costCommands
O(1)SET GET INCRBY STRLEN GETSET · DEL EXISTS TYPE RENAME EXPIRE TTL · RPUSH/LPUSH RPOP/LPOP BRPOP/BLPOP RPOPLPUSH · HSET HMSET HGET HINCRBY · SADD SPOP
O(N)MGET MSET (N = number of keys) · LINDEX LRANGE · HGETALL (N = size of the hash) · SMEMBERS (N = size of the set) · SINTER SUNION SDIFF
O(log(N))ZADD ZRANK ZRANGEBYSCORE ZINCRBY ZREMRANGEBYSCORE

The pattern has a reason (Redis documentation, background). A key is found by hashing, so anything that touches one key and one element is O(1). A list is linked, so its two ends are cheap and its middle is not: LINDEX and LRANGE walk it. A set is a hash table, so SISMEMBER is O(1) where a list scan is O(N). A sorted set keeps its members in order in a skip list, so inserting and finding by score take O(log(N)). Commands that hand back a whole structure, SMEMBERS or HGETALL, are O(N) in its size.

A Redis to try things on

Reading replies is one skill; predicting them is the one the exam needs. The console below runs a small Redis inside this page, with every command of this lesson, and replays the slides' sessions and the five papers one line at a time.

A Redis in your page

Type a command and press Enter, or pick a script and run it line by line, predicting each reply before it appears. Every key is a card with its name, its type, its clock and its elements; a list shows both indexes of each element. Time stands still until you move it: Let time run makes one second pass per second, +1 s and +10 s jump ahead, and Reset empties the database. Replies follow redis-cli; a few rarely used commands are not implemented, and the console says so.

  1. Pick "Exam 13 Jun 2025: Instrument" and press Run next line until EXPIRE instruments 10 has run. Predict: after the eleven seconds that follow, what do SISMEMBER instruments "Keyboard" and TTL instruments answer? Then run the rest.
    What you should see

    0 and -2. At t = 10 s the log reports that the key instruments expired, with all four members, and its card disappears. The insight this console is built for: a TTL belongs to a key, so everything stored under the key goes at once.

  2. Pick "Slide p. 357: the list jobs". Before you run LPUSH jobs "bar", predict its reply (the slide prints (integer) 1). Go on until BLPOP jobs.
    What you should see

    (integer) 2, the length after the push. BLPOP jobs, typed as the slide prints it, gets (error) ERR wrong number of arguments for 'blpop' command: the timeout is missing. BLPOP proc 0 at the end returns the name of the list and the element.

  3. Type RPUSH r a b c and LPUSH l a b c, and predict the order on each card. Then predict LRANGE r 0 -2 and LRANGE l -2 -1 before you run them.
    What you should see

    r reads a b c and l reads c b a; under each element the card shows its index from the head and from the tail. LRANGE r 0 -2 gives a, b (all but the last); LRANGE l -2 -1 gives b, a (the last two of l).

  4. Pick "Two traps: EX where it does not belong". Predict the reply of SADD instruments "Flute" EX 10, and what TTL instruments answers after it.
    What you should see

    (integer) 3 and -1. SADD has no options, so "Flute", "EX" and "10" all became members and no clock was set. HSET … EX 100 does the same with a field called "EX". Only SET takes EX; every other structure needs a separate EXPIRE.

The flute, settled

Back to the hook. Eleven seconds after EXPIRE instruments 10, SISMEMBER instruments "Keyboard" answers 0. The clock was armed on the key instruments; at t = 10 s Redis deleted the key, and with it every member — Keyboard, Violin and Drums as well as Flute. TTL instruments now answers -2.

instruments Keyboard Violin Drums Flute TTL 10 s SISMEMBER instruments "Keyboard" → 1

t = 0 s, right after EXPIRE instruments 10

instruments Keyboard Violin Drums Flute TTL -2 the whole set is gone SISMEMBER instruments "Keyboard" → 0

t = 10 s, the clock has run out

Fig. 6. EXPIRE armed one clock, on the key instruments. When it ran out, Redis deleted the key — and every member under it, not only Flute. TTL now answers -2, and SISMEMBER answers 0 for any instrument.

So the safe answer is two commands and one sentence: SADD instruments "Flute", EXPIRE instruments 10, and "in Redis a TTL belongs to a key, so the whole set expires after 10 seconds; a single member cannot have its own". If only Flute should go, it needs a key of its own, such as SET instrument:Flute "Flute" EX 10. What must not be written is SADD instruments "Flute" EX 10: SADD has no options, and Redis adds two more members, "EX" and "10".

A TTL belongs to a key, never to one member of a list, a set or a sorted set.

Exam-style questions

The five Redis exercises of the past papers, each after the part of its ER diagram that it uses, then two theory questions in the forms of the written exam. No solutions are published: the model answers are ours, and every command and reply in them was checked on an emulation of Redis.

Exam of 24 Jun 2024, exercise 5 — Redis (3 PT). ER (tracking Disney's digital products), the part used: Script (ID, Length, Duration, Title) and Line (ID, Sequence Number, Text), linked by Include: Script 1:N – Line 1:1.

"Consider the Line table. Write the Redis code to create a new list of lines involving the lines "Hey you", "Watch out", and "Hello there". (1 PT)"

"Write the Redis operation to collect the first three lines in the list. (1 PT)"

"Write the Redis operations to create a new key-value pair named "Line #0001" with the value "A long time ago in a galaxy far, far away" and check its lifespan. (1 PT)."

Show model answer
RPUSH lines "Hey you" "Watch out" "Hello there"
LRANGE lines 0 2
SET "Line #0001" "A long time ago in a galaxy far, far away"
TTL "Line #0001"

Redis answers (integer) 3; then the three lines in the order given; then OK and (integer) -1, because a key created with a plain SET has no expiry.

What to get right: RPUSH, because LPUSH would store the lines reversed and the "first three" would start with "Hello there"; the inclusive stop of LRANGE (0 2 is three elements, 0 3 would ask for four); quotes around a key that contains a space; and TTL for "check its lifespan" — saying that the answer is -1 shows that you know what it means.

Exam of 21 Jan 2025, exercise 4 — Redis (4 PT). ER (tracking Netflix's digital content), the part used: Book (ID, name, number_volumes, publication_date); Write: Book 1:1 – Writer 1:N; Inspired: Cartoon 0:1 – Book 0:N.

"Consider the Book entity and write the commands for the following operations. Create a key-value pair with "best_book", the value "La ragazza delle Arance", and TTL equal to 100 (1 PT)"

"Check the TTL of the key-value pair "best_book" and make it permanently stored (1 PT)"

"Assume there exists a set named "HP Books" that includes all the Harry Potter books besides the first one. Add the movie "Harry Potter and the Philosopher Stone" to the set. (1 PT)"

"Check if the last movie "Harry Potter and the Deadly Hallows" is part of the set (1 PT)"

Show model answer
SET best_book "La ragazza delle Arance" EX 100
TTL best_book
PERSIST best_book
SADD "HP Books" "Harry Potter and the Philosopher Stone"
SISMEMBER "HP Books" "Harry Potter and the Deadly Hallows"

Replies: OK; the seconds left (at most 100), then (integer) 1, after which TTL best_book would answer -1; (integer) 1, one new member; (integer) 1 if the title is in the set, as it should be since the set holds every book but the first, otherwise 0. SET best_book "La ragazza delle Arance" followed by EXPIRE best_book 100 is an equally correct first answer.

What to get right: EX or EXPIRE for the TTL; TTL before PERSIST, since the item asks to check and then to make permanent; the quotes around HP Books; SISMEMBER, not SMEMBERS, for "check if". "Permanently stored" means no expiry, not a disk write. Redis compares exact strings: the paper writes "Deadly Hallows" for the Deathly Hallows, so the spelling must match the one stored in the set.

Exam of 13 Jun 2025, exercise 4 — Redis (3 PT). ER (tracking concert attendances and performances), the part used: Instrument (Name, Type (e.g., chordophones), Description); Play – Since: Musician (1,N) – Instrument (1,N).

"Consider the entity Instrument. Create a set of instruments including "Keyboard", "Violin", and "Drums" (1 PT)"

"Perform an operation to check whether "Flute" is part of the set (1 PT)"

"Perform an operation to add "Flute" to the set, with time to live equal to 10 (1 PT)"

Show model answer
SADD instruments "Keyboard" "Violin" "Drums"
SISMEMBER instruments "Flute"
SADD instruments "Flute"
EXPIRE instruments 10

Replies: (integer) 3; (integer) 0; (integer) 1 and (integer) 1. In Redis a time to live belongs to a key, not to a member: EXPIRE makes the whole set (Keyboard, Violin, Drums and Flute) disappear after 10 seconds. If only Flute must expire, it needs a key of its own, for example SET instrument:Flute "Flute" EX 10.

No marking scheme is published, so make the sentence part of the answer: saying what EXPIRE really does shows that you know where a TTL lives. An answer that writes SADD instruments "Flute" EX 10 adds two extra members, "EX" and "10", and sets no clock at all.

Exam of 12 Sep 2025, exercise 4 — Redis (three items of 1 PT). ER (tracking farmers and their sales at local markets), the part used: Animal (Tag, Name, Age, Animal Type (e.g., Cow), Breed); House – Housing Date: Animal (1, 1) – Farm (1, N).

"Consider the Animal entity. Create a list "Farm" with two animals named "Bessy" and "Bob" (1 PT)"

"Write the code to create a new element "Dog" with value "Jerry" that will expire in 1000 seconds. (1 PT)"

"Write the code to check whether the animal "Bob" is in a list of animals named "Farm" (1 PT)"

Show model answer
RPUSH Farm "Bessy" "Bob"
SET Dog "Jerry" EX 1000
LPOS Farm "Bob"

Replies: (integer) 2; OK; (integer) 1, the position of "Bob" ((nil) if it were missing). LPOS needs Redis 6.0.6 or later and is not in the slides; with the slides' commands, read the list with LRANGE Farm 0 -1 and look for "Bob". A set with SISMEMBER would answer this test in one step: that is what sets are for.

The list is the paper's choice, and lists are weak at membership: both answers walk the list, O(N). The sentence about sets shows that you know why. "An element that will expire in 1000 seconds" is a string with a clock: SET … EX 1000, or SET then EXPIRE Dog 1000.

Exam of 30 Jan 2026, exercise 5 — Redis (5 PT). ER (a hospital heating management system), the part used: Hospital (Hospital_ID, Name); Department (Department_ID, Specialty, N_Beds, Head_Physician_ID), with Has Dept.: Hospital 1:N – Department 1:1; Heating System (Heater_Sys_ID, Heating_Power) with the children HVAC System (Hourly_KWh_Cons, Cost_Per_KWh) and Gas Heating System (Hourly_SQM_Cons, Cost_Per_SQM), ISA (T, E), and Has H. Sys.: Hospital 1:N – Heating System 1:1.

"Create a single key-value pair to store all the data of one Gas Heater, with a TTL of 100, and with all the attributes describing the object. (1 PT)"

"Create a list to store all Department specialties, sorted by their foundation year. Then, query the list to get the older one. (2 PT)"

"Create a set to store all Department specialties for Hospital1. Then, create another set to store all Department specialties for Hospital2. Finally, combine the two sets to obtain the complete collection of specialties available across both hospitals. (2 PT)"

Show model answer
HSET gas_heater:GH01 Heater_Sys_ID GH01 Heating_Power 24 Hourly_SQM_Cons 0.8 Cost_Per_SQM 0.12
EXPIRE gas_heater:GH01 100
ZADD specialties 1921 "Cardiology" 1950 "Neurology" 1975 "Oncology"
ZRANGE specialties 0 0
SADD hospital1:specialties "Cardiology" "Oncology"
SADD hospital2:specialties "Cardiology" "Neurology"
SUNION hospital1:specialties hospital2:specialties

The values are examples: the paper gives only the attributes. Replies: (integer) 4 and (integer) 1; (integer) 3 and "Cardiology", the lowest score; (integer) 2, (integer) 2 and the three specialties Cardiology, Oncology and Neurology, in any order.

(a) One key with all the attributes is a hash: the four attributes of a gas heating system, two of them inherited from Heating System, become fields, and EXPIRE is a second command because HSET has no EX. One string holding a JSON document, SET gas_heater:GH01 '{…}' EX 100, also keeps everything under one key. (b) Department has no foundation year in the diagram: assume the attribute, as the readme of the papers asks when a paper has a gap. The paper says "list", but only a sorted set keeps the order by itself; a list pushed in year order with RPUSH and read with LRANGE specialties 0 0 also returns the oldest — say which one you use and why. (c) SUNION returns the union; SUNIONSTORE all:specialties hospital1:specialties hospital2:specialties keeps it under a new key.

Redis offers INCR and INCRBY, although a client could read a value with GET, add one, and write it back with SET. Why are these commands needed? Explain what "atomic" means here and why Redis can guarantee it.

Show model answer

GET, +1 and SET are three separate steps: the client reads the value, computes the new one on its side and writes it back. Between the read and the write another client can read the same old value, so two concurrent increments both write 11 over 10 and one of them is lost. INCR performs the read, the increment and the write inside the server, as one command. An atomic operation is indivisible: no other client's command can run in the middle of it, so it is not affected by concurrent access. Redis can guarantee this because it is a single-threaded server that executes one command at a time — no two commands can run at the same time — so every single command is atomic without any lock, and two INCR commands always add 2. The same holds for DECR, INCRBY, DECRBY and HINCRBY.

A complete answer names three things: the lost update as the concrete problem, "atomic" defined as indivisible with respect to other clients, and the single thread as the reason. "Redis locks the key" is wrong: there is no lock, there is simply no other command running.

A key is created with SET session "abc" EX 60. Twenty seconds later a client runs SET session "xyz". What does TTL session return right after?

  • 40 That would need the new SET to keep the old clock. A plain SET removes it (only the KEEPTTL option, not used in the course, would keep it).
  • 60 The slide's "whenever the key is SET, the TTL is reset" does not mean that the old clock starts again: it is removed.
  • -1 A plain SET replaces the value and drops the timeout: the key is now permanent.
  • -2 -2 means that there is no such key; this key exists, it was just overwritten.
Show model answer

-1. SET overwrites the value and discards any time to live unless the new SET carries its own EX; the key now never expires.

The trap is the word "reset" on p. 1595. A wrong closed answer may cost points: if you hesitate between 40 and 60, remember that a plain SET writes a brand-new value without a clock.

Check yourself

The list q is built with RPUSH q "a", then RPUSH q "b", then RPUSH q "c". What does LPOP q return?

  • "a" RPUSH appends at the tail and LPOP takes from the head: first in, first out — a queue.
  • "c" "c" sits at the tail; RPOP would return it. Taking from the end you pushed to is the stack pattern.
  • "b" LPOP never takes from the middle: a pop works only at the two ends, which is why it is O(1).
  • (nil) The list holds three elements; (nil) comes only from an empty or missing list.

The list jobs has a TTL of 50 seconds. Which commands leave its clock running? Select all that apply.

  • RPUSH jobs "x" It changes the list in place, and the timeout stays.
  • RENAME jobs work The value moves to the new name and takes its clock along.
  • SET jobs "done" SET replaces the list with a string and drops the clock: "whenever the key is SET, the TTL is reset" (p. 1595).
  • PERSIST jobs PERSIST is the command that removes the clock.

Change the value in place: the clock stays. Replace the value, or PERSIST: the clock goes.

The list l holds a b c d e. What does LRANGE l 1 -2 return?

  • b c d Start at index 1 (b), stop at -2 (d, the second to last), both ends included.
  • b c That is Python's l[1:-2], which stops before its end index; LRANGE includes it.
  • a b c d The start is 1, not 0, so a is skipped.
  • c d Index 1 is the second element, b: LRANGE counts from 0.

The key tags does not exist yet. What does SADD tags "red" "blue" "red" answer?

  • (integer) 2 Two values were really added; when the second "red" came, it was already a member.
  • (integer) 3 A set keeps each value once, and the reply counts only the values actually added.
  • (integer) 1 The session's "Returns 1 if the element is correctly added" describes one value; with several, the reply is a count.
  • an error Duplicates are not an error: they are simply ignored.

A system must always show the three products with the highest sales, and the sales change every minute. Which structure fits best?

  • A sorted set with the sales as score ZINCRBY updates a score in O(log(N)) and keeps the order; ZRANGE sales -3 -1 reads the three highest.
  • A list A list keeps insertion order, not sales order: every update would mean finding and moving the element yourself.
  • A set A set has no order at all.
  • A hash with one field per product The fields are not ordered either; you would read them all with HGETALL and sort them yourself.

Why can two INCR from two clients on the same key never lose an update?

  • Redis runs one command at a time, and INCR reads, adds and writes inside one command "no two commands can run at the same time" (p. 352): the second INCR starts only after the first has written.
  • Redis locks the key while a client uses it There are no locks: while a command runs, nothing else runs.
  • The client retries INCR until it succeeds Nothing is retried; INCR cannot fail because of another client.
  • Redis keeps a version number for every key No versions are involved: the single thread is the whole reason.

TTL k answers -2. What can be true? Select all that apply.

  • k expired The slide's own reading: "The key has already expired".
  • k was removed with DEL A deleted key does not exist either.
  • k never existed TTL answers -2 for any key that does not exist.
  • k exists but has no expiry That answer is -1.

-2 says one thing: there is no such key now.

Key take-aways

What to watch and read