Lists
A list is an ordered sequence of strings. You add and remove elements at either end, read ranges by position, and can block until an element arrives. Lists suit job queues, stacks, activity feeds (“the last 100 events”), and handing work from producers to consumers.
Elements keep the order you inserted them in, duplicates are allowed, and
positions start at 0 from the head (left). Negative positions count from the
tail: -1 is the last element.
Create, read, update, delete
Section titled “Create, read, update, delete”There is no separate create step: pushing to a missing key creates the list, and a list whose last element is removed is deleted.
127.0.0.1:6379> RPUSH tasks "resize:1" "resize:2" "resize:3"(integer) 3127.0.0.1:6379> LPUSH tasks "urgent:9"(integer) 4127.0.0.1:6379> LRANGE tasks 0 -11) "urgent:9"2) "resize:1"3) "resize:2"4) "resize:3"127.0.0.1:6379> LLEN tasks(integer) 4127.0.0.1:6379> LINDEX tasks -1"resize:3"127.0.0.1:6379> LSET tasks 1 "resize:1b"OK127.0.0.1:6379> LPOP tasks"urgent:9"127.0.0.1:6379> RPOP tasks 21) "resize:3"2) "resize:2"127.0.0.1:6379> LPOP tasks"resize:1b"127.0.0.1:6379> EXISTS tasks(integer) 0To change the middle of a list, use LINSERT to add before or after a given element, LREM to remove occurrences of a value, and LPOS to find where a value is.
127.0.0.1:6379> RPUSH letters a b c b(integer) 4127.0.0.1:6379> LPOS letters b(integer) 1127.0.0.1:6379> LPOS letters b COUNT 01) (integer) 12) (integer) 3127.0.0.1:6379> LINSERT letters BEFORE c x(integer) 5127.0.0.1:6379> LREM letters 0 b(integer) 2127.0.0.1:6379> LRANGE letters 0 -11) "a"2) "x"3) "c"LPUSHX and RPUSHX push only when the list already exists.
Common patterns
Section titled “Common patterns”Queue (first in, first out). Producers RPUSH, consumers LPOP.
Stack (last in, first out). Push and pop at the same end.
Capped feed. Keep only the newest N items by trimming after each push:
127.0.0.1:6379> LPUSH feed:user:42 "liked post 7"(integer) 1127.0.0.1:6379> LTRIM feed:user:42 0 99OKReliable processing. LMOVE pops from one list and
pushes onto another atomically. Move a job from jobs:pending to
jobs:processing, and remove it from there with LREM once it is done.
If a worker dies, the job is still in jobs:processing for another worker
to pick up.
127.0.0.1:6379> RPUSH jobs:pending "job:1" "job:2"(integer) 2127.0.0.1:6379> LMOVE jobs:pending jobs:processing LEFT RIGHT"job:1"127.0.0.1:6379> LREM jobs:processing 1 "job:1"(integer) 1Pop from several lists. LMPOP pops from the first non-empty list among the keys you name, which lets you poll queues in priority order.
Blocking consumers
Section titled “Blocking consumers”Instead of polling, a consumer can wait for work. BLPOP
and BRPOP block until one of the lists has an element
or the timeout (in seconds, fractions allowed, 0 for no limit) passes.
The reply names the list the element came from.
127.0.0.1:6379> BLPOP jobs:high jobs:pending 51) "jobs:pending"2) "job:2"127.0.0.1:6379> BLPOP jobs:high jobs:pending 1(nil)The second call found both lists empty, waited one second, and timed out.
BLMOVE and BLMPOP are the blocking
forms of LMOVE and LMPOP. See
Blocking operations for how waiting
clients are served.
Expiry
Section titled “Expiry”A time to live applies to the whole list: set it with
EXPIRE and friends. Single elements cannot expire. If
you need per-item expiry, use a sorted set
scored by timestamp and remove old members with ZREMRANGEBYSCORE, or a
hash with field TTLs.
Pushing to or popping from a list keeps its time to live. Removing the last element deletes the key, and with it the expiry.
Limits and performance
Section titled “Limits and performance”Each element is a string up to proto-max-bulk-len (512 MB by default).
Pushing and popping at either end take constant time. Commands that work by
position or by value (LINDEX, LSET, LINSERT, LREM, LPOS) walk the
list, so they get slower as the list grows; for large collections that you
look up by value, a set or
sorted set is the better fit. LRANGE costs
grow with the number of elements returned, so read big lists in pages.
Commands
Section titled “Commands”| Command | What it does |
|---|---|
| LPUSH / RPUSH | Add elements at the head or tail |
| LPUSHX / RPUSHX | Add only if the list exists |
| LPOP / RPOP | Remove and return elements from the head or tail |
| LMPOP | Pop from the first non-empty list |
| LLEN | Number of elements |
| LRANGE | Elements in a range of positions |
| LINDEX | Element at a position |
| LSET | Replace the element at a position |
| LINSERT | Insert before or after an element |
| LREM | Remove occurrences of a value |
| LPOS | Positions of a value |
| LTRIM | Keep only a range of positions |
| LMOVE | Move an element between lists |
| RPOPLPUSH | Older form of LMOVE ... RIGHT LEFT |
| BLPOP / BRPOP | Blocking pop |
| BLMOVE / BRPOPLPUSH | Blocking move |
| BLMPOP | Blocking pop from several lists |
From your application
Section titled “From your application”import hotkv
client = hotkv.HotKV(host="localhost", port=6379, decode_responses=True)
client.rpush("jobs:pending", "job:1", "job:2")job = client.lmove("jobs:pending", "jobs:processing", "LEFT", "RIGHT")print(job) # job:1print(client.lrange("jobs:processing", 0, -1))
# Wait up to 5 seconds for work on either queue.print(client.blpop(["jobs:high", "jobs:pending"], 5))client.close()import { HotKV } from "@hotkv/client";
const client = new HotKV({ url: "hotkv://127.0.0.1:6379" });
await client.rPush("jobs:pending", "job:1", "job:2");const job = await client.lMove("jobs:pending", "jobs:processing", "LEFT", "RIGHT");console.log(job);console.log(await client.lRange("jobs:processing", 0, -1));
// Wait up to 5 seconds for work on either queue.console.log(await client.blPop(["jobs:high", "jobs:pending"], 5));await client.close();client, err := hotkv.NewClient(&hotkv.Options{Addr: "localhost:6379"})if err != nil { log.Fatal(err)}defer client.Close()ctx := context.Background()
client.RPush(ctx, "jobs:pending", "job:1", "job:2")job, _ := client.LPop(ctx, "jobs:pending").Result()fmt.Println(job)
items, _ := client.LRange(ctx, "jobs:pending", 0, -1).Result()fmt.Println(items)
// Wait up to 5 seconds for work on either queue.res, err := client.BLPop(ctx, 5*time.Second, "jobs:high", "jobs:pending").Result()fmt.Println(res, err)import com.hotkv.HotKV;
try (HotKV client = HotKV.create("hotkv://localhost:6379")) { client.rpush("jobs:pending", "job:1", "job:2"); String job = client.lmove("jobs:pending", "jobs:processing", "LEFT", "RIGHT"); System.out.println(job); System.out.println(client.lrange("jobs:processing", 0, -1));}Was this page helpful?
Thanks for the feedback.