RENAME

Summary: Renames a key and overwrites the destination.

Overview

This command's behavior varies in clustered Redis environments. See the [multi-key operations]() page for more information.

Renames `key` to `newkey`.
It returns an error when `key` does not exist.
If `newkey` already exists it is overwritten, when this happens `RENAME` executes an implicit [`DEL`]() operation, so if the deleted key contains a very big value it may cause high latency even if `RENAME` itself is usually a constant-time operation.

In Cluster mode, both `key` and `newkey` must be in the same **hash slot**, meaning that in practice only keys that have the same hash tag can be reliably renamed in cluster.

Examples

SET mykey "Hello"
RENAME mykey myotherkey
GET myotherkey

Behavior change history

*   `>= 3.2.0`: The command no longer returns an error when source and destination names are the same.

Redis Software and Redis Cloud compatibility

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
<nobr>✅ Active-Active\*</nobr> | ✅ Standard
<nobr>✅ Active-Active\*</nobr> | For Active-Active or clustered databases, the original key and new key must be in the same hash slot.

\*Not supported for stream consumer group info. |

Return information

**RESP2:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): `OK`.

**RESP3:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): `OK`.


RENAMENX

Summary: Renames a key only when the target key name doesn't exist.

Overview

This command's behavior varies in clustered Redis environments. See the [multi-key operations]() page for more information.

Renames `key` to `newkey` if `newkey` does not yet exist.
It returns an error when `key` does not exist.

In Cluster mode, both `key` and `newkey` must be in the same **hash slot**, meaning that in practice only keys that have the same hash tag can be reliably renamed in cluster.

Examples

SET mykey "Hello"
SET myotherkey "World"
RENAMENX mykey myotherkey
GET myotherkey

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
<nobr>✅ Active-Active</nobr> | ✅ Standard
<nobr>✅ Active-Active</nobr> | For Active-Active or clustered databases, the original key and new key must be in the same hash slot. |

Return information

**RESP2:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): `1` if _key_ was renamed to _newkey_.
* [Integer reply](../../develop/reference/protocol-spec#integers): `0` if _newkey_ already exists.

**RESP3:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): `1` if _key_ was renamed to _newkey_.
* [Integer reply](../../develop/reference/protocol-spec#integers): `0` if _newkey_ already exists.


REPLCONF

Summary: An internal command for configuring the replication stream.

Overview

The `REPLCONF` command is an internal command.
It is used by a Redis master to configure a connected replica.

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ❌ Standard
<nobr>❌ Active-Active</nobr> | ❌ Standard
<nobr>❌ Active-Active</nobr> |  |

Return information


REPLICAOF

Summary: Configures a server as replica of another, or promotes it to a master.

Overview

The `REPLICAOF` command can change the replication settings of a replica on the fly.

If a Redis server is already acting as replica, the command `REPLICAOF` NO ONE will turn off the replication, turning the Redis server into a MASTER.  In the proper form `REPLICAOF` hostname port will make the server a replica of another server listening at the specified hostname and port.

If a server is already a replica of some master, `REPLICAOF` hostname port will stop the replication against the old server and start the synchronization against the new one, discarding the old dataset.

The form `REPLICAOF` NO ONE will stop replication, turning the server into a MASTER, but will not discard the already replicated data. So, if the old master stops working, it is possible to turn the replica into a master and set the application to use this new master in read/write. Later when the other Redis server is fixed, it can be reconfigured to work as a replica.

Examples

[code example]

Return information

> REPLICAOF NO ONE
"OK"

> REPLICAOF 127.0.0.1 6799
"OK"


RESET

Summary: Resets the connection.

Overview

This command performs a full reset of the connection's server-side context,
mimicking the effect of disconnecting and reconnecting again.

When the command is called from a regular client connection, it does the
following:

* Discards the current [`MULTI`]() transaction block, if one exists.
* Unwatches all keys [`WATCH`]()ed by the connection.
* Disables [`CLIENT TRACKING`](), if in use.
* Sets the connection to [`READWRITE`]() mode.
* Cancels the connection's [`ASKING`]() mode, if previously set.
* Sets [`CLIENT REPLY`]() to `ON`.
* Sets the protocol version to RESP2.
* [`SELECT`]()s database 0.
* Exits [`MONITOR`]() mode, when applicable.
* Aborts Pub/Sub's subscription state ([`SUBSCRIBE`]() and [`PSUBSCRIBE`]()), when
  appropriate.
* Deauthenticates the connection, requiring a call [`AUTH`]() to reauthenticate when
  authentication is enabled.
* Turns off `NO-EVICT` mode.
* Turns off `NO-TOUCH` mode.

Return information

**RESP2:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): `RESET`.

**RESP3:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): `RESET`.


RESTORE

Summary: Creates a key from the serialized representation of a value.

Overview

Create a key associated with a value that is obtained by deserializing the
provided serialized value (obtained via [`DUMP`]()).

If `ttl` is 0 the key is created without any expire, otherwise the specified
expire time (in milliseconds) is set.

If the `ABSTTL` modifier was used, `ttl` should represent an absolute
[Unix timestamp][hewowu] (in milliseconds) in which the key will expire.

[hewowu]: http://en.wikipedia.org/wiki/Unix_time

For eviction purposes, you may use the `IDLETIME` or `FREQ` modifiers. See
[`OBJECT`]() for more information.

`RESTORE` will return a "Target key name is busy" error when `key` already
exists unless you use the `REPLACE` modifier.

`RESTORE` checks the RDB version and data checksum.
If they don't match an error is returned.

Examples

[code example]

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
❌ Active-Active\*</nobr> | ✅ Standard
❌ Active-Active\*</nobr> | \*Only supported for module keys. |

Return information


RESTORE-ASKING

Summary: An internal command for migrating keys in a cluster.

Overview

The `RESTORE-ASKING` command is an internal command.
It is used by a Redis cluster master during slot migration.


ROLE

Summary: Returns the replication role.

Overview

Provide information on the role of a Redis instance in the context of replication, by returning if the instance is currently a `master`, `slave`, or `sentinel`. The command also returns additional information about the state of the replication (if the role is master or slave) or the list of monitored master names (if the role is sentinel).

Output format

The command returns an array of elements. The first element is the role of
the instance, as one of the following three strings:

* "master"
* "slave"
* "sentinel"

The additional elements of the array depends on the role.

Master output

An example of output when `ROLE` is called in a master instance:

[code example]

The master output is composed of the following parts:

1. The string `master`.
2. The current master replication offset, which is an offset that masters and replicas share to understand, in partial resynchronizations, the part of the replication stream the replicas needs to fetch to continue.
3. An array composed of three elements array representing the connected replicas. Every sub-array contains the replica IP, port, and the last acknowledged replication offset.

Output of the command on replicas

An example of output when `ROLE` is called in a replica instance:

[code example]

The replica output is composed of the following parts:

1. The string `slave`, because of backward compatibility (see note at the end of this page).
2. The IP of the master.
3. The port number of the master.
4. The state of the replication from the point of view of the master, that can be `connect` (the instance needs to connect to its master), `connecting` (the master-replica connection is in progress), `sync` (the master and replica are trying to perform the synchronization), `connected` (the replica is online).
5. The amount of data received from the replica so far in terms of master replication offset.

Sentinel output

An example of Sentinel output:

[code example]

The sentinel output is composed of the following parts:

1. The string `sentinel`.
2. An array of master names monitored by this Sentinel instance.

Examples

ROLE

**A note about the word slave used in this man page**: Starting with Redis 5, if not for backward compatibility, the Redis project no longer uses the word slave. Unfortunately in this command the word slave is part of the protocol, so we'll be able to remove such occurrences only when this API will be naturally deprecated.

Return information

**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): where the first element is one of `master`, `slave`, or `sentinel`, and the additional elements are role-specific as illustrated above.

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): where the first element is one of `master`, `slave`, or `sentinel`, and the additional elements are role-specific as illustrated above.

1) "sentinel"
2) 1) "resque-master"
   2) "html-fragments-master"
   3) "stats-master"
   4) "metadata-master"


RPOP

Summary: Returns and removes the last elements of a list. Deletes the list if the last element was popped.

Examples

#### Code Examples

Foundational: Remove and return the last element(s) from a list using RPOP (supports optional count parameter to pop multiple elements from tail)

**Difficulty:** Beginner

**Commands:** RPUSH, RPOP, LRANGE

**Complexity:**
- RPUSH: O(1)
- RPOP: O(N)
- LRANGE: O(S+N)

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C# (Synchronous), Go, Java (Asynchronous - Lettuce), Java (Reactive - Lettuce), Java (Synchronous - Jedis), JavaScript (Node.js), PHP, Python

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java (Asynchronous - Lettuce):**

[code example]

**Java (Reactive - Lettuce):**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

Give these commands a try in the interactive console:

RPUSH mylist "one" "two" "three" "four" "five"
RPOP mylist
RPOP mylist 2
LRANGE mylist 0 -1

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
<nobr>✅ Active-Active</nobr> | ✅ Standard
<nobr>✅ Active-Active</nobr> |  |

Return information

**RESP2:**

One of the following:
* [Nil reply](../../develop/reference/protocol-spec#bulk-strings): if the key does not exist.
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): when called without the _count_ argument, the value of the last element.
* [Array reply](../../develop/reference/protocol-spec#arrays): when called with the _count_ argument, a list of popped elements.

**RESP3:**

One of the following:
* [Null reply](../../develop/reference/protocol-spec#nulls): if the key does not exist.
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): when called without the _count_ argument, the value of the last element.
* [Array reply](../../develop/reference/protocol-spec#arrays): when called with the _count_ argument, a list of popped elements.

redis> RPUSH mylist "one" "two" "three" "four" "five"
(integer) 5
redis> RPOP mylist
"five"
redis> RPOP mylist 2
1) "four"
2) "three"
redis> LRANGE mylist 0 -1
1) "one"
2) "two"

long rPopResult1 = db.ListRightPush("mylist", ["one", "two", "three", "four", "five"]);
        Console.WriteLine(rPopResult1); // >>> 5

        RedisValue rPopResult2 = db.ListRightPop("mylist");
        Console.WriteLine(rPopResult2); // >>> five

        RedisValue[] rPopResult3 = db.ListRightPop("mylist", 2);
        Console.WriteLine($"[{string.Join(", ", rPopResult3)}]");
        // >>> [four, three]

        RedisValue[] rPopResult4 = db.ListRange("mylist", 0, -1);
        Console.WriteLine($"[{string.Join(", ", rPopResult4)}]");
        // >>> [one, two]

rPushResult, err := rdb.RPush(ctx, "mylist",
		"one", "two", "three", "four", "five",
	).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(rPushResult) // >>> 5

	rPopResult, err := rdb.RPop(ctx, "mylist").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(rPopResult) // >>> five

	rPopCountResult, err := rdb.RPopCount(ctx, "mylist", 2).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(rPopCountResult) // >>> [four three]

	lRangeResult, err := rdb.LRange(ctx, "mylist", 0, -1).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(lRangeResult) // >>> [one two]

CompletableFuture<Void> rpop = asyncCommands.rpush("mylist", "one", "two", "three", "four", "five")
                    .thenCompose(res18 -> {
                        System.out.println(res18); // >>> 5

                        return asyncCommands.rpop("mylist");
                    }).thenCompose(res19 -> {
                        System.out.println(res19); // >>> five

                        return asyncCommands.rpop("mylist", 2);
                    }).thenCompose(res20 -> {
                        System.out.println(res20); // >>> [four, three]

                        return asyncCommands.lrange("mylist", 0, -1);
                    })
                    .thenAccept(res21 -> System.out.println(res21)) // >>> [one, two]
                    .toCompletableFuture();

Mono<Void> rpop = reactiveCommands.rpush("mylist", "one", "two", "three", "four", "five").doOnNext(res18 -> {
                System.out.println(res18); // >>> 5
            }).flatMap(res18 -> reactiveCommands.rpop("mylist")).doOnNext(res19 -> {
                System.out.println(res19); // >>> five
            }).flatMap(res19 -> reactiveCommands.rpop("mylist", 2).collectList()).doOnNext(res20 -> {
                System.out.println(res20); // >>> [four, three]
            }).flatMap(res20 -> reactiveCommands.lrange("mylist", 0, -1).collectList()).doOnNext(res21 -> {
                System.out.println(res21); // >>> [one, two]
            }).then();

long rPopResult1 = jedis.rpush(
            "mylist", "one", "two", "three", "four", "five"
        );
        System.out.println(rPopResult1); // >>> 5

        String rPopResult2 = jedis.rpop("mylist");
        System.out.println(rPopResult2); // >>> five

        List<String> rPopResult3 = jedis.rpop("mylist", 2);
        System.out.println(rPopResult3); // >>> [four, three]

        List<String> rPopResult4 = jedis.lrange("mylist", 0, -1);
        System.out.println(rPopResult4); // >>> [one, two]

const res21 = await client.rPush('mylist', ["one", "two", "three", "four", "five"]);
console.log(res21); // 5

const res22 = await client.rPop('mylist');
console.log(res22); // 'five'

const res23 = await client.rPopCount('mylist', 2);
console.log(res23); // [ 'four', 'three' ]

const res24 = await client.lRange('mylist', 0, -1);
console.log(res24); // [ 'one', 'two' ]

$res21 = $r->rpush('mylist', 'one', 'two', 'three', 'four', 'five');
        echo $res21 . PHP_EOL;
        // >>> 5

        $res22 = $r->rpop('mylist');
        echo $res22 . PHP_EOL;
        // >>> five

        $res23 = $r->rpop('mylist', 2);
        echo json_encode($res23) . PHP_EOL;
        // >>> ["four","three"]

        $res24 = $r->lrange('mylist', 0, -1);
        echo json_encode($res24) . PHP_EOL;
        // >>> ["one","two"]

res18 = r.rpush("mylist", *["one", "two", "three", "four", "five"])
print(res18) # >>> 5

res19 = r.rpop("mylist")
print(res19) # >>> "five"

res20 = r.rpop("mylist", 2)
print(res20) # >>> ['four', 'three']

res21 = r.lrange("mylist", 0, -1)
print(res21)  # >>> [ "one", "two" ]


RPOPLPUSH

Summary: Returns the last element of a list after removing and pushing it to another list. Deletes the list if the last element was popped.

Overview

This command's behavior varies in clustered Redis environments. See the [multi-key operations]() page for more information.

Atomically returns and removes the last element (tail) of the list stored at
`source`, and pushes the element at the first element (head) of the list stored
at `destination`.

For example: consider `source` holding the list `a,b,c`, and `destination`
holding the list `x,y,z`.
Executing `RPOPLPUSH` results in `source` holding `a,b` and `destination`
holding `c,x,y,z`.

If `source` does not exist, the value `nil` is returned and no operation is
performed.
If `source` and `destination` are the same, the operation is equivalent to
removing the last element from the list and pushing it as first element of the
list, so it can be considered as a list rotation command.

Examples

RPUSH mylist "one"
RPUSH mylist "two"
RPUSH mylist "three"
RPOPLPUSH mylist myotherlist
LRANGE mylist 0 -1
LRANGE myotherlist 0 -1

Pattern: Reliable queue

Redis is often used as a messaging server to implement processing of background
jobs or other kinds of messaging tasks.
A simple form of queue is often obtained pushing values into a list in the
producer side, and waiting for this values in the consumer side using [`RPOP`]()
(using polling), or [`BRPOP`]() if the client is better served by a blocking
operation.

However in this context the obtained queue is not _reliable_ as messages can
be lost, for example in the case there is a network problem or if the consumer
crashes just after the message is received but before it can be processed.

`RPOPLPUSH` (or [`BRPOPLPUSH`]() for the blocking variant) offers a way to avoid
this problem: the consumer fetches the message and at the same time pushes it
into a _processing_ list.
It will use the [`LREM`]() command in order to remove the message from the
_processing_ list once the message has been processed.

An additional client may monitor the _processing_ list for items that remain
there for too much time, pushing timed out items into the queue
again if needed.

Pattern: Circular list

Using `RPOPLPUSH` with the same source and destination key, a client can visit
all the elements of an N-elements list, one after the other, in O(N) without
transferring the full list from the server to the client using a single [`LRANGE`]()
operation.

The above pattern works even if one or both of the following conditions occur:

* There are multiple clients rotating the list: they'll fetch different
  elements, until all the elements of the list are visited, and the process
  restarts.
* Other clients are actively pushing new items at the end of the list.

The above makes it very simple to implement a system where a set of items must
be processed by N workers continuously as fast as possible.
An example is a monitoring system that must check that a set of web sites are
reachable, with the smallest delay possible, using a number of parallel workers.

Note that this implementation of workers is trivially scalable and reliable,
because even if a message is lost the item is still in the queue and will be
processed at the next iteration.

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
<nobr>✅ Active-Active</nobr> | ✅ Standard
<nobr>✅ Active-Active</nobr> | Deprecated as of Redis v6.2.0. |

Return information

**RESP2:**

One of the following:
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): the element being popped and pushed.
* [Nil reply](../../develop/reference/protocol-spec#bulk-strings): if the source list is empty.

**RESP3:**

One of the following:
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): the element being popped and pushed.
* [Null reply](../../develop/reference/protocol-spec#nulls): if the source list is empty.


RPUSH

Summary: Appends one or more elements to a list. Creates the key if it doesn't exist.

Examples

#### Code Examples

Foundational: Add one or more elements to the tail of a list using RPUSH (creates list if needed, returns new list length)

**Difficulty:** Beginner

**Commands:** RPUSH, LRANGE

**Complexity:**
- RPUSH: O(1)
- LRANGE: O(S+N)

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C# (Synchronous), Go, Java (Asynchronous - Lettuce), Java (Reactive - Lettuce), Java (Synchronous - Jedis), JavaScript (Node.js), PHP, Python

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java (Asynchronous - Lettuce):**

[code example]

**Java (Reactive - Lettuce):**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

Give these commands a try in the interactive console:

RPUSH mylist "hello"
RPUSH mylist "world"
LRANGE mylist 0 -1

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): the length of the list after the push operation.

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): the length of the list after the push operation.

redis> RPUSH mylist "hello"
(integer) 1
redis> RPUSH mylist "world"
(integer) 2
redis> LRANGE mylist 0 -1
1) "hello"
2) "world"

long rPushResult1 = db.ListRightPush("mylist", "hello");
        Console.WriteLine(rPushResult1); // >>> 1

        long rPushResult2 = db.ListRightPush("mylist", "world");
        Console.WriteLine(rPushResult2); // >>> 2

        RedisValue[] rPushResult3 = db.ListRange("mylist", 0, -1);
        Console.WriteLine($"[{string.Join(", ", rPushResult3)}]");
        // >>> [hello, world]

rPushResult1, err := rdb.RPush(ctx, "mylist", "Hello").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(rPushResult1) // >>> 1

	rPushResult2, err := rdb.RPush(ctx, "mylist", "World").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(rPushResult2) // >>> 2

	lRangeResult, err := rdb.LRange(ctx, "mylist", 0, -1).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(lRangeResult) // >>> [Hello World]

CompletableFuture<Void> rpush = asyncCommands.rpush("mylist", "hello").thenCompose(res14 -> {
                System.out.println(res14); // >>> 1

                return asyncCommands.rpush("mylist", "world");
            }).thenCompose(res15 -> {
                System.out.println(res15); // >>> 2

                return asyncCommands.lrange("mylist", 0, -1);
            })
                    .thenAccept(res16 -> System.out.println(res16)) // >>> [hello, world]
                    .toCompletableFuture();

Mono<Void> rpush = reactiveCommands.rpush("mylist", "hello").doOnNext(res14 -> {
                System.out.println(res14); // >>> 1
            }).flatMap(res14 -> reactiveCommands.rpush("mylist", "world")).doOnNext(res15 -> {
                System.out.println(res15); // >>> 2
            }).flatMap(res15 -> reactiveCommands.lrange("mylist", 0, -1).collectList()).doOnNext(res16 -> {
                System.out.println(res16); // >>> [hello, world]
            }).then();

long rPushResult1 = jedis.rpush("mylist", "hello");
        System.out.println(rPushResult1); // >>> 1

        long rPushResult2 = jedis.rpush("mylist", "world");
        System.out.println(rPushResult2); // >>> 2

        List<String> rPushResult3 = jedis.lrange("mylist", 0, -1);
        System.out.println(rPushResult3); // >>> [hello, world]

const res14 = await client.rPush('mylist', 'hello');
console.log(res14); // 1

const res15 = await client.rPush('mylist', 'world');
console.log(res15); // 2

const res16 = await client.lRange('mylist', 0, -1);
console.log(res16); // [ 'hello', 'world' ]

$res14 = $r->rpush('mylist', 'hello');
        echo $res14 . PHP_EOL;
        // >>> 1

        $res15 = $r->rpush('mylist', 'world');
        echo $res15 . PHP_EOL;
        // >>> 2

        $res16 = $r->lrange('mylist', 0, -1);
        echo json_encode($res16) . PHP_EOL;
        // >>> ["hello","world"]

res14 = r.rpush("mylist", "hello")
print(res14) # >>> 1

res15 = r.rpush("mylist", "world")
print(res15) # >>> 2

res16 = r.lrange("mylist", 0, -1)
print(res16)  # >>> [ "hello", "world" ]


RPUSHX

Summary: Appends an element to a list only when the list exists.

Overview

Inserts specified values at the tail of the list stored at `key`, only if `key`
already exists and holds a list.
In contrary to [`RPUSH`](), no operation will be performed when `key` does not yet
exist.

Examples

RPUSH mylist "Hello"
RPUSHX mylist "World"
RPUSHX myotherlist "World"
LRANGE mylist 0 -1
LRANGE myotherlist 0 -1

Return information


SADD

Summary: Adds one or more members to a set. Creates the key if it doesn't exist.

Examples

#### Code Examples

Foundational: Add one or more members to a set using SADD (creates set if needed, ignores duplicates, returns count of new members)

**Difficulty:** Beginner

**Commands:** SADD, SMEMBERS

**Complexity:**
- SADD: O(1)
- SMEMBERS: O(N)

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C# (Synchronous), Go, Java (Asynchronous - Lettuce), Java (Reactive - Lettuce), Java (Synchronous - Jedis), JavaScript (Node.js), PHP, Python

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java (Asynchronous - Lettuce):**

[code example]

**Java (Reactive - Lettuce):**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

Give these commands a try in the interactive console:

SADD myset "Hello" "World"
SADD myset "World"
SMEMBERS myset

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): the number of elements that were added to the set, not including all the elements already present in the set.

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): the number of elements that were added to the set, not including all the elements already present in the set.

redis> SADD myset "Hello" "World"
(integer) 2
redis> SADD myset "World"
(integer) 0
redis> SMEMBERS myset
1) "Hello"
2) "World"

bool sAddResult1 = db.SetAdd("myset", "Hello");
        Console.WriteLine(sAddResult1); // >>> True

        bool sAddResult2 = db.SetAdd("myset", "World");
        Console.WriteLine(sAddResult2); // >>> True

        bool sAddResult3 = db.SetAdd("myset", "World");
        Console.WriteLine(sAddResult2); // >>> False

        RedisValue[] sAddResult4 = db.SetMembers("myset");
        Array.Sort(sAddResult4);
        Console.WriteLine(string.Join(", ", sAddResult4));
        // >>> Hello, World

sAddResult1, err := rdb.SAdd(ctx, "myset", "Hello").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(sAddResult1) // >>> 1

	sAddResult2, err := rdb.SAdd(ctx, "myset", "World").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(sAddResult2) // >>> 1

	sAddResult3, err := rdb.SAdd(ctx, "myset", "World").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(sAddResult3) // >>> 0

	sMembersResult, err := rdb.SMembers(ctx, "myset").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(sMembersResult) // >>> [Hello World]

CompletableFuture<Void> sadd = asyncCommands.sadd("myset", "Hello").thenCompose(r -> {
                System.out.println(r); // >>> 1
                return asyncCommands.sadd("myset", "World");
            }).thenCompose(r -> {
                System.out.println(r); // >>> 1
                return asyncCommands.sadd("myset", "World");
            }).thenCompose(r -> {
                System.out.println(r); // >>> 0
                return asyncCommands.smembers("myset");
            })
                    .thenAccept(System.out::println)
                    // >>> [Hello, World]
                    .toCompletableFuture();

Mono<Void> sadd = reactiveCommands.sadd("myset", "Hello").doOnNext(r -> {
                System.out.println(r); // >>> 1
            }).flatMap(r -> reactiveCommands.sadd("myset", "World")).doOnNext(r -> {
                System.out.println(r); // >>> 1
            }).flatMap(r -> reactiveCommands.sadd("myset", "World")).doOnNext(r -> {
                System.out.println(r); // >>> 0
            }).flatMap(r -> reactiveCommands.smembers("myset").collectList()).doOnNext(r -> {
                System.out.println(r); // >>> [Hello, World]
            }).then();

long sAddResult1 = jedis.sadd("myset", "Hello");
        System.out.println(sAddResult1); // >>> 1

        long sAddResult2 = jedis.sadd("myset", "World");
        System.out.println(sAddResult2); // >>> 1

        long sAddResult3 = jedis.sadd("myset", "World");
        System.out.println(sAddResult3); // >>> 0

        Set<String> sAddResult4 = jedis.smembers("myset");
        System.out.println(sAddResult4.stream().sorted().collect(toList()));
        // >>> [Hello, World]

const res1 = await client.sAdd('myset', ['Hello', 'World']);
console.log(res1);  // 2

const res2 = await client.sAdd('myset', ['World']);
console.log(res2);  // 0

const res3 = await client.sMembers('myset')
console.log(res3);  // ['Hello', 'World']

$res1 = $r->sadd('myset', ['Hello', 'World']);
        echo $res1 . PHP_EOL;
        // >>> 2

        $res2 = $r->sadd('myset', ['World']);
        echo $res2 . PHP_EOL;
        // >>> 0

        $res3 = $r->smembers('myset');
        sort($res3);
        echo json_encode($res3) . PHP_EOL;
        // >>> ["Hello","World"]

res1 = r.sadd("myset", "Hello", "World")
print(res1)  # >>> 2

res2 = r.sadd("myset", "World")
print(res2)  # >>> 0

res3 = r.smembers("myset")
print(res3)  # >>> {'Hello', 'World'}


SAVE

Summary: Synchronously saves the database(s) to disk.

Overview

The `SAVE` commands performs a **synchronous** save of the dataset producing a
_point in time_ snapshot of all the data inside the Redis instance, in the form
of an RDB file.

You almost never want to call `SAVE` in production environments where it will
block all the other clients.
Instead usually [`BGSAVE`]() is used.
However in case of issues preventing Redis to create the background saving child
(for instance errors in the fork(2) system call), the `SAVE` command can be a
good last resort to perform the dump of the latest dataset.

See the [persistence documentation]() for detailed information.

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ❌ Standard
<nobr>❌ Active-Active</nobr> | ❌ Standard
<nobr>❌ Active-Active</nobr> |  |

Return information

**RESP2:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): `OK`.

**RESP3:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): `OK`.


SCAN

Summary: Iterates over the key names in the database.

SCAN basic usage

SCAN is a cursor based iterator. This means that at every call of the command, the server returns an updated cursor that the user needs to use as the cursor argument in the next call.

An iteration starts when the cursor is set to 0, and terminates when the cursor returned by the server is 0. The following is an example of SCAN iteration:

[code example]

In the example above, the first call uses zero as a cursor, to start the iteration. The second call uses the cursor returned by the previous call as the first element of the reply, that is, 17.

As you can see the **SCAN return value** is an array of two values: the first value is the new cursor to use in the next call, the second value is an array of elements.

Since in the second call the returned cursor is 0, the server signaled to the caller that the iteration finished, and the collection was completely explored. Starting an iteration with a cursor value of 0, and calling `SCAN` until the returned cursor is 0 again is called a **full iteration**.

Return value

`SCAN`, [`SSCAN`](), [`HSCAN`]() and [`ZSCAN`]() return a two element multi-bulk reply, where the first element is a string representing an unsigned 64 bit number (the cursor), and the second element is a multi-bulk with an array of elements.

* `SCAN` array of elements is a list of keys.
* [`SSCAN`]() array of elements is a list of Set members.
* [`HSCAN`]() array of elements contain two elements, a field and a value, for every returned element of the Hash.
* [`ZSCAN`]() array of elements contain two elements, a member and its associated score, for every returned element of the Sorted Set.

Scan guarantees

The `SCAN` command, and the other commands in the `SCAN` family, are able to provide to the user a set of guarantees associated to full iterations.

* A full iteration always retrieves all the elements that were present in the collection from the start to the end of a full iteration. This means that if a given element is inside the collection when an iteration is started, and is still there when an iteration terminates, then at some point `SCAN` returned it to the user.
* A full iteration never returns any element that was NOT present in the collection from the start to the end of a full iteration. So if an element was removed before the start of an iteration, and is never added back to the collection for all the time an iteration lasts, `SCAN` ensures that this element will never be returned.

However because `SCAN` has very little state associated (just the cursor) it has the following drawbacks:

* A given element may be returned multiple times. It is up to the application to handle the case of duplicated elements, for example only using the returned elements in order to perform operations that are safe when re-applied multiple times.
* Elements that were not constantly present in the collection during a full iteration, may be returned or not: it is undefined.

Number of elements returned at every SCAN call

`SCAN` family functions do not guarantee that the number of elements returned per call are in a given range. The commands are also allowed to return zero elements, and the client should not consider the iteration complete as long as the returned cursor is not zero.

However the number of returned elements is reasonable, that is, in practical terms `SCAN` may return a maximum number of elements in the order of a few tens of elements when iterating a large collection, or may return all the elements of the collection in a single call when the iterated collection is small enough to be internally represented as an encoded data structure (this happens for small Sets, Hashes and Sorted Sets).

However there is a way for the user to tune the order of magnitude of the number of returned elements per call using the **COUNT** option.

The COUNT option

While `SCAN` does not provide guarantees about the number of elements returned at every iteration, it is possible to empirically adjust the behavior of `SCAN` using the **COUNT** option. Basically with COUNT the user specifies the *amount of work that should be done at every call in order to retrieve elements from the collection*. This is **just a hint** for the implementation, however generally speaking this is what you could expect most of the times from the implementation.

* The default `COUNT` value is 10.
* When iterating the key space, or a Set, Hash or Sorted Set that is big enough to be represented by a hash table, assuming no **MATCH** option is used, the server will usually return *count* or a few more than *count* elements per call. Please check the *why SCAN may return all the elements at once* section later in this document.
* When iterating Sets encoded as intsets (small sets composed of just integers), or Hashes and Sorted Sets encoded as ziplists (small hashes and sets composed of small individual values), usually all the elements are returned in the first `SCAN` call regardless of the `COUNT` value.

Important: **there is no need to use the same COUNT value** for every iteration. The caller is free to change the count from one iteration to the other as required, as long as the cursor passed in the next call is the one obtained in the previous call to the command.

The MATCH option

It is possible to only iterate elements matching a given glob-style pattern, similarly to the behavior of the [`KEYS`]() command that takes a pattern as its only argument.

To do so, just append the `MATCH <pattern>` arguments at the end of the `SCAN` command (it works with all the `SCAN` family commands).

This is an example of iteration using **MATCH**:

#### Code Examples

Set iteration: Iterate set members with pattern matching using SSCAN MATCH (cursor-based iteration, non-blocking)

**Difficulty:** Intermediate

**Commands:** SADD, SSCAN

**Complexity:**
- SADD: O(1)
- SSCAN: O(1)

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Synchronous), Go, Java (Asynchronous - Lettuce), Java (Reactive - Lettuce), Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java (Asynchronous - Lettuce):**

[code example]

**Java (Reactive - Lettuce):**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

It is important to note that the **MATCH** filter is applied after elements are retrieved from the collection, just before returning data to the client. This means that if the pattern matches very little elements inside the collection, `SCAN` will likely return no elements in most iterations. An example is shown below:

#### Code Examples

Keyspace iteration: Iterate database keys with pattern matching using SCAN MATCH and COUNT (demonstrates cursor iteration with sparse results)

**Difficulty:** Intermediate

**Commands:** SCAN

**Complexity:**
- SCAN: O(1)

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Synchronous), Go, Java (Asynchronous - Lettuce), Java (Reactive - Lettuce), Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java (Asynchronous - Lettuce):**

[code example]

**Java (Reactive - Lettuce):**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

As you can see most of the calls returned zero elements, but the last call where a `COUNT` of 1000 was used in order to force the command to do more scanning for that iteration.

When using [Redis Cluster](), the search is optimized for patterns that imply a single slot.
If a pattern can only match keys of one slot,
Redis only iterates over keys in that slot, rather than the whole database,
when searching for keys matching the pattern.
For example, with the pattern `{a}h*llo`, Redis would only try to match it with the keys in slot 15495, which hash tag `{a}` implies.
To use pattern with hash tag, see [Hash tags]() in the Cluster specification for more information.

The TYPE option

You can use the `TYPE` option to ask `SCAN` to only return objects that match a given `type`, allowing you to iterate through the database looking for keys of a specific type. The **TYPE** option is only available on the whole-database `SCAN`, not [`HSCAN`]() or [`ZSCAN`]() etc.

The `type` argument is the same string name that the [`TYPE`]() command returns. Note a quirk where some Redis types, such as GeoHashes, HyperLogLogs, Bitmaps, and Bitfields, may internally be implemented using other Redis types, such as a string or zset, so can't be distinguished from other keys of that same type by `SCAN`. For example, a ZSET and GEOHASH:

#### Code Examples

Iterate keyspace by type: Iterate database keys filtered by type using SCAN TYPE (filters keys by data type, useful for type-specific operations)

**Difficulty:** Intermediate

**Commands:** GEOADD, ZADD, TYPE, SCAN

**Complexity:**
- GEOADD: O(log(N)
- ZADD: O(log(N)
- TYPE: O(1)
- SCAN: O(1)

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Synchronous), Go, Java (Asynchronous - Lettuce), Java (Reactive - Lettuce), Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java (Asynchronous - Lettuce):**

[code example]

**Java (Reactive - Lettuce):**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

It is important to note that the **TYPE** filter is also applied after elements are retrieved from the database, so the option does not reduce the amount of work the server has to do to complete a full iteration, and for rare types you may receive no elements in many iterations.

The NOVALUES option

When using [`HSCAN`](), you can use the `NOVALUES` option to make Redis return only the keys in the hash table without their corresponding values.

#### Code Examples

Hash iteration: Iterate hash fields with optional NOVALUES using HSCAN (returns field-value pairs or fields only)

**Difficulty:** Intermediate

**Commands:** HSET, HSCAN

**Complexity:**
- HSET: O(1)
- HSCAN: O(1)

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Synchronous), Go, Java (Asynchronous - Lettuce), Java (Reactive - Lettuce), Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java (Asynchronous - Lettuce):**

[code example]

**Java (Reactive - Lettuce):**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

Multiple parallel iterations

It is possible for an infinite number of clients to iterate the same collection at the same time, as the full state of the iterator is in the cursor, that is obtained and returned to the client at every call. No server side state is taken at all.

Terminating iterations in the middle

Since there is no state server side, but the full state is captured by the cursor, the caller is free to terminate an iteration half-way without signaling this to the server in any way. An infinite number of iterations can be started and never terminated without any issue.

Calling SCAN with a corrupted cursor

Calling `SCAN` with a broken, negative, out of range, or otherwise invalid cursor, will result in undefined behavior but never in a crash. What will be undefined is that the guarantees about the returned elements can no longer be ensured by the `SCAN` implementation.

The only valid cursors to use are:

* The cursor value of 0 when starting an iteration.
* The cursor returned by the previous call to SCAN in order to continue the iteration.

Guarantee of termination

The `SCAN` algorithm is guaranteed to terminate only if the size of the iterated collection remains bounded to a given maximum size, otherwise iterating a collection that always grows may result into `SCAN` to never terminate a full iteration.

This is easy to see intuitively: if the collection grows there is more and more work to do in order to visit all the possible elements, and the ability to terminate the iteration depends on the number of calls to `SCAN` and its COUNT option value compared with the rate at which the collection grows.

Why SCAN may return all the items of an aggregate data type in a single call?

In the `COUNT` option documentation, we state that sometimes this family of commands may return all the elements of a Set, Hash or Sorted Set at once in a single call, regardless of the `COUNT` option value. The reason why this happens is that the cursor-based iterator can be implemented, and is useful, only when the aggregate data type that we are scanning is represented as a hash table. However Redis uses a [memory optimization]() where small aggregate data types, until they reach a given amount of items or a given max size of single elements, are represented using a compact single-allocation packed encoding. When this is the case, `SCAN` has no meaningful cursor to return, and must iterate the whole data structure at once, so the only sane behavior it has is to return everything in a call.

However once the data structures are bigger and are promoted to use real hash tables, the `SCAN` family of commands will resort to the normal behavior. Note that since this special behavior of returning all the elements is true only for small aggregates, it has no effects on the command complexity or latency. However the exact limits to get converted into real hash tables are [user configurable](), so the maximum number of elements you can see returned in a single call depends on how big an aggregate data type could be and still use the packed representation.

Also note that this behavior is specific of [`SSCAN`](), [`HSCAN`]() and [`ZSCAN`](). `SCAN` itself never shows this behavior because the key space is always represented by hash tables.

Further reading

For more information about managing keys, please refer to the [The Redis Keyspace]() tutorial.

Additional examples

Give the following commands, showing iteration of a hash key, a try in the interactive console:

HMSET hash name Jack age 33
HSCAN hash 0

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
<nobr>✅ Active-Active</nobr> | ✅ Standard
<nobr>✅ Active-Active</nobr> |  |

Return information

**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): specifically, an array with two elements.
* The first element is a [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings) that represents an unsigned 64-bit number, the cursor.
* The second element is an [Array reply](../../develop/reference/protocol-spec#arrays) with the names of scanned keys.

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): specifically, an array with two elements.
* The first element is a [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings) that represents an unsigned 64-bit number, the cursor.
* The second element is an [Array reply](../../develop/reference/protocol-spec#arrays) with the names of scanned keys.

> sadd myset 1 2 3 foo foobar feelsgood
(integer) 6
> sscan myset 0 match f*
1) "0"
2) 1) "foo"
   2) "feelsgood"
   3) "foobar"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis/hiredis.h>

int main(int argc, char **argv) {
    redisContext *c = redisConnect("127.0.0.1", 6379);

    if (c == NULL || c->err) {
        if (c) {
            printf("Connection error: %s\n", c->errstr);
            redisFree(c);
        } else {
            printf("Connection error: can't allocate redis context\n");
        }
        return 1;
    }

    redisReply *reply;

    // Set up keys
    reply = redisCommand(c, "MSET %s %s %s %s %s %s",
        "firstname", "Jack", "lastname", "Stuntman", "age", "35");
    printf("MSET firstname Jack lastname Stuntman age 35: %s\n", reply->str);
    // >>> OK
    freeReplyObject(reply);

    // Keys matching *name*
    reply = redisCommand(c, "KEYS %s", "*name*");
    printf("KEYS *name*:\n");
    for (size_t i = 0; i < reply->elements; i++) {
        printf("  %s\n", reply->element[i]->str);
    }
    // >>> firstname
    // >>> lastname
    freeReplyObject(reply);

    // Keys matching a??
    reply = redisCommand(c, "KEYS %s", "a??");
    printf("KEYS a??:\n");
    for (size_t i = 0; i < reply->elements; i++) {
        printf("  %s\n", reply->element[i]->str);
    }
    // >>> age
    freeReplyObject(reply);

    // All keys
    reply = redisCommand(c, "KEYS %s", "*");
    printf("KEYS *:\n");
    for (size_t i = 0; i < reply->elements; i++) {
        printf("  %s\n", reply->element[i]->str);
    }
    // >>> age
    // >>> firstname
    // >>> lastname
    freeReplyObject(reply);

    redisFree(c);

    return 0;
}

package example_commands_test

import (
	"context"
	"fmt"
	"math"
	"sort"
	"time"

	"github.com/redis/go-redis/v9"
)

func ExampleClient_del_cmd() {
	ctx := context.Background()

	rdb := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password docs
		DB:       0,  // use default DB
	})

	delResult1, err := rdb.Set(ctx, "key1", "Hello", 0).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(delResult1) // >>> OK

	delResult2, err := rdb.Set(ctx, "key2", "World", 0).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(delResult2) // >>> OK

	delResult3, err := rdb.Del(ctx, "key1", "key2", "key3").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(delResult3) // >>> 2

}

func ExampleClient_exists_cmd() {
	ctx := context.Background()

	rdb := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password docs
		DB:       0,  // use default DB
	})

	existsResult1, err := rdb.Set(ctx, "key1", "Hello", 0).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(existsResult1) // >>> OK

	existsResult2, err := rdb.Exists(ctx, "key1").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(existsResult2) // >>> 1

	existsResult3, err := rdb.Exists(ctx, "nosuchkey").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(existsResult3) // >>> 0

	existsResult4, err := rdb.Set(ctx, "key2", "World", 0).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(existsResult4) // >>> OK

	existsResult5, err := rdb.Exists(ctx, "key1", "key2", "nosuchkey").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(existsResult5) // >>> 2

}

func ExampleClient_expire_cmd() {
	ctx := context.Background()

	rdb := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password docs
		DB:       0,  // use default DB
	})

	expireResult1, err := rdb.Set(ctx, "mykey", "Hello", 0).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(expireResult1) // >>> OK

	expireResult2, err := rdb.Expire(ctx, "mykey", 10*time.Second).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(expireResult2) // >>> true

	expireResult3, err := rdb.TTL(ctx, "mykey").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(math.Round(expireResult3.Seconds())) // >>> 10

	expireResult4, err := rdb.Set(ctx, "mykey", "Hello World", 0).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(expireResult4) // >>> OK

	expireResult5, err := rdb.TTL(ctx, "mykey").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(expireResult5) // >>> -1ns

	expireResult6, err := rdb.ExpireXX(ctx, "mykey", 10*time.Second).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(expireResult6) // >>> false

	expireResult7, err := rdb.TTL(ctx, "mykey").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(expireResult7) // >>> -1ns

	expireResult8, err := rdb.ExpireNX(ctx, "mykey", 10*time.Second).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(expireResult8) // >>> true

	expireResult9, err := rdb.TTL(ctx, "mykey").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(math.Round(expireResult9.Seconds())) // >>> 10

}

func ExampleClient_keys_cmd() {
	ctx := context.Background()

	rdb := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password docs
		DB:       0,  // use default DB
	})

	keysResult1, err := rdb.MSet(ctx, "firstname", "Jack", "lastname", "Stuntman", "age", "35").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(keysResult1) // >>> OK

	keysResult2, err := rdb.Keys(ctx, "*name*").Result()

	if err != nil {
		panic(err)
	}

	sort.Strings(keysResult2)
	fmt.Println(keysResult2) // >>> [firstname lastname]

	keysResult3, err := rdb.Keys(ctx, "a??").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(keysResult3) // >>> [age]

	keysResult4, err := rdb.Keys(ctx, "*").Result()

	if err != nil {
		panic(err)
	}

	sort.Strings(keysResult4)
	fmt.Println(keysResult4) // >>> [age firstname lastname]

}

func ExampleClient_ttl_cmd() {
	ctx := context.Background()

	rdb := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password docs
		DB:       0,  // use default DB
	})

	ttlResult1, err := rdb.Set(ctx, "mykey", "Hello", 10*time.Second).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(ttlResult1) // >>> OK

	ttlResult2, err := rdb.TTL(ctx, "mykey").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(math.Round(ttlResult2.Seconds())) // >>> 10

}

package io.redis.examples.async;

import io.lettuce.core.*;

import io.lettuce.core.api.async.RedisAsyncCommands;

import io.lettuce.core.api.StatefulRedisConnection;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

public class CmdsGenericExample {

    public void run() {

            CompletableFuture<Void> existsExample = asyncCommands.set("key1", "Hello").thenCompose(res1 -> {
                System.out.println(res1); // >>> OK

                return asyncCommands.exists("key1");
            }).thenCompose(res2 -> {
                System.out.println(res2); // >>> 1

                return asyncCommands.exists("nosuchkey");
            }).thenCompose(res3 -> {
                System.out.println(res3); // >>> 0

                return asyncCommands.set("key2", "World");
            }).thenCompose(res4 -> {
                System.out.println(res4); // >>> OK

                return asyncCommands.exists("key1", "key2", "nosuchkey");
            }).thenAccept(res5 -> {
                System.out.println(res5); // >>> 2
            }).toCompletableFuture();
            existsExample.join();

            CompletableFuture<Void> keysExample = asyncCommands.mset(Map.of(
                    "firstname", "Jack",
                    "lastname", "Stuntman",
                    "age", "35"
            )).thenCompose(res1 -> {
                System.out.println(res1); // >>> OK

                return asyncCommands.keys("*name*");
            }).thenCompose(res2 -> {
                Collections.sort(res2);
                System.out.println(res2); // >>> [firstname, lastname]

                return asyncCommands.keys("a??");
            }).thenCompose(res3 -> {
                System.out.println(res3); // >>> [age]

                return asyncCommands.keys("*");
            }).thenAccept(res4 -> {
                Collections.sort(res4);
                System.out.println(res4); // >>> [age, firstname, lastname]
            }).toCompletableFuture();
            keysExample.join();
        } finally {
            redisClient.shutdown();
        }
    }
}

package io.redis.examples.reactive;

import io.lettuce.core.*;
import io.lettuce.core.api.reactive.RedisReactiveCommands;
import io.lettuce.core.api.StatefulRedisConnection;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.Map;

public class CmdsGenericExample {

    public void run() {
        RedisClient redisClient = RedisClient.create("redis://localhost:6379");

        try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {
            RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();

            Mono<Void> existsExample = reactiveCommands.set("key1", "Hello").doOnNext(res1 -> {
                System.out.println(res1); // >>> OK
            }).then(reactiveCommands.exists("key1")).doOnNext(res2 -> {
                System.out.println(res2); // >>> 1
            }).then(reactiveCommands.exists("nosuchkey")).doOnNext(res3 -> {
                System.out.println(res3); // >>> 0
            }).then(reactiveCommands.set("key2", "World")).doOnNext(res4 -> {
                System.out.println(res4); // >>> OK
            }).then(reactiveCommands.exists("key1", "key2", "nosuchkey")).doOnNext(res5 -> {
                System.out.println(res5); // >>> 2
            }).then();

            Mono.when(existsExample).block();

            Mono<Void> keysExample = reactiveCommands.mset(Map.of(
                    "firstname", "Jack",
                    "lastname", "Stuntman",
                    "age", "35"
            )).doOnNext(res1 -> {
                System.out.println(res1); // >>> OK
            }).then(reactiveCommands.keys("*name*").collectList()).doOnNext(res2 -> {
                Collections.sort(res2);
                System.out.println(res2); // >>> [firstname, lastname]
            }).then(reactiveCommands.keys("a??").collectList()).doOnNext(res3 -> {
                System.out.println(res3); // >>> [age]
            }).then(reactiveCommands.keys("*").collectList()).doOnNext(res4 -> {
                Collections.sort(res4);
                System.out.println(res4); // >>> [age, firstname, lastname]
            }).then();

            Mono.when(keysExample).block();

        } finally {
            redisClient.shutdown();
        }
    }

}

import redis.clients.jedis.RedisClient;
import redis.clients.jedis.args.ExpiryOption;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class CmdsGenericExample {

    public void run() {
        RedisClient jedis = RedisClient.create("redis://localhost:6379");

        String delResult1 = jedis.set("key1", "Hello");
        System.out.println(delResult1); // >>> OK

        String delResult2 = jedis.set("key2", "World");
        System.out.println(delResult2); // >>> OK

        long delResult3 = jedis.del("key1", "key2", "key3");
        System.out.println(delResult3); // >>> 2

        // Tests for 'del' step.

        String existsResult1 = jedis.set("key1", "Hello");
        System.out.println(existsResult1); // >>> OK

        boolean existsResult2 = jedis.exists("key1");
        System.out.println(existsResult2); // >>> true

        boolean existsResult3 = jedis.exists("nosuchkey");
        System.out.println(existsResult3); // >>> false

        String existsResult4 = jedis.set("key2", "World");
        System.out.println(existsResult4); // >>> OK

        long existsResult5 = jedis.exists("key1", "key2", "nosuchkey");
        System.out.println(existsResult5); // >>> 2

        // Tests for 'exists' step.

        String expireResult1 = jedis.set("mykey", "Hello");
        System.out.println(expireResult1);  // >>> OK

        long expireResult2 = jedis.expire("mykey", 10);
        System.out.println(expireResult2);  // >>> 1

        long expireResult3 = jedis.ttl("mykey");
        System.out.println(expireResult3);  // >>> 10

        String expireResult4 = jedis.set("mykey", "Hello World");
        System.out.println(expireResult4);  // >>> OK

        long expireResult5 = jedis.ttl("mykey");
        System.out.println(expireResult5);  // >>> -1

        long expireResult6 = jedis.expire("mykey", 10, ExpiryOption.XX);
        System.out.println(expireResult6);  // >>> 0

        long expireResult7 = jedis.ttl("mykey");
        System.out.println(expireResult7);  // >>> -1

        long expireResult8 = jedis.expire("mykey", 10, ExpiryOption.NX);
        System.out.println(expireResult8);  // >>> 1

        long expireResult9 = jedis.ttl("mykey");
        System.out.println(expireResult9);  // >>> 10

        // Tests for 'expire' step.

        String ttlResult1 = jedis.set("mykey", "Hello");
        System.out.println(ttlResult1); // >>> OK

        long ttlResult2 = jedis.expire("mykey", 10);
        System.out.println(ttlResult2); // >>> 1

        long ttlResult3 = jedis.ttl("mykey");
        System.out.println(ttlResult3); // >>> 10

        // Tests for 'ttl' step.

        String keysResult1 = jedis.mset("firstname", "Jack", "lastname", "Stuntman", "age", "35");
        System.out.println(keysResult1); // >>> OK

        Set<String> keysResult2 = jedis.keys("*name*");
        ArrayList<String> keysResult2List = new ArrayList<>(keysResult2);
        Collections.sort(keysResult2List);
        System.out.println(keysResult2List); // >>> [firstname, lastname]

        Set<String> keysResult3 = jedis.keys("a??");
        System.out.println(keysResult3); // >>> [age]

        Set<String> keysResult4 = jedis.keys("*");
        ArrayList<String> keysResult4List = new ArrayList<>(keysResult4);
        Collections.sort(keysResult4List);
        System.out.println(keysResult4List); // >>> [age, firstname, lastname]

        // Tests for 'keys' step.

        jedis.close();
    }
}

const scan1Res1 = await client.sAdd('myset', ['1', '2', '3', 'foo', 'foobar', 'feelsgood']);
console.log(scan1Res1); // 6

let scan1Res2 = [];
for await (const values of client.sScanIterator('myset', { MATCH: 'f*' })) {
    scan1Res2 = scan1Res2.concat(values);
}
console.log(scan1Res2); // ['foo', 'foobar', 'feelsgood']

import assert from 'node:assert';
import { Redis } from 'ioredis';

const redis = new Redis();

const keysRes1 = await redis.mset({ firstname: 'Jack', lastname: 'Stuntman', age: '35' });
console.log(keysRes1); // >>> OK

const keysRes2 = await redis.keys('*name*');
console.log(keysRes2.sort()); // >>> ['firstname', 'lastname']

const keysRes3 = await redis.keys('a??');
console.log(keysRes3); // >>> ['age']

const keysRes4 = await redis.keys('*');
console.log(keysRes4.sort()); // >>> ['age', 'firstname', 'lastname']

redis.disconnect();

<?php
use PHPUnit\Framework\TestCase;
use Predis\Client as PredisClient;

class CmdsGenericTest
{
    public function testCmdsGeneric() {
        $r = new PredisClient([
            'scheme'   => 'tcp',
            'host'     => '127.0.0.1',
            'port'     => 6379,
            'password' => '',
            'database' => 0,
        ]);

        $existsResult1 = $r->set('key1', 'Hello');
        echo $existsResult1 . PHP_EOL; // >>> OK

        $existsResult2 = $r->exists('key1');
        echo $existsResult2 . PHP_EOL; // >>> 1

        $existsResult3 = $r->exists('nosuchkey');
        echo $existsResult3 . PHP_EOL; // >>> 0

        $existsResult4 = $r->set('key2', 'World');
        echo $existsResult4 . PHP_EOL; // >>> OK

        $existsResult5 = $r->exists('key1', 'key2', 'nosuchkey');
        echo $existsResult5 . PHP_EOL; // >>> 2

        $keysResult1 = $r->mset(['firstname' => 'Jack', 'lastname' => 'Stuntman', 'age' => '35']);
        echo $keysResult1 . PHP_EOL; // >>> OK

        $keysResult2 = $r->keys('*name*');
        sort($keysResult2);
        echo implode(', ', $keysResult2) . PHP_EOL; // >>> firstname, lastname

        $keysResult3 = $r->keys('a??');
        echo implode(', ', $keysResult3) . PHP_EOL; // >>> age

        $keysResult4 = $r->keys('*');
        sort($keysResult4);
        echo implode(', ', $keysResult4) . PHP_EOL; // >>> age, firstname, lastname

    }
}

res = r.sadd("myset", *set([1, 2, 3, "foo", "foobar", "feelsgood"]))
print(res)
# >>> 6

res = list(r.sscan_iter("myset", match="f*"))
print(res)
# >>> ['foobar', 'foo', 'feelsgood']

match r.sadd("myset", &["1", "2", "3", "foo", "foobar", "feelsgood"]).await {
            Ok(res) => {
                let res: i32 = res;
                println!("{res}");    // >>> 6
            },
            Err(e) => {
                println!("Error adding to set: {e}");
                return;
            }
        }

        let res = match r.sscan_match("myset", "f*").await {
            Ok(iter) => {
                let res: Vec<Result<String, _>> = iter.collect().await;
                res.into_iter().filter_map(|r| r.ok()).collect::<Vec<String>>()
            },
            Err(e) => {
                println!("Error scanning set: {e}");
                return;
            }
        };

        println!("{res:?}");    // >>> ["foo", "foobar", "feelsgood"]

match r.sadd("myset", &["1", "2", "3", "foo", "foobar", "feelsgood"]) {
            Ok(res) => {
                let res: i32 = res;
                println!("{res}");    // >>> 6
            },
            Err(e) => {
                println!("Error adding to set: {e}");
                return;
            }
        }

        match r.sscan_match("myset", "f*") {
            Ok(iter) => {
                let res: Vec<String> = iter.filter_map(|r| r.ok()).collect();
                println!("{res:?}");    // >>> ["foo", "foobar", "feelsgood"]
            },
            Err(e) => {
                println!("Error scanning set: {e}");
                return;
            }
        }

let cursor = '0';
let scanResult;

scanResult = await client.scan(cursor, { MATCH: '*11*' });
console.log(scanResult.cursor, scanResult.keys);

scanResult = await client.scan(scanResult.cursor, { MATCH: '*11*' });
console.log(scanResult.cursor, scanResult.keys);

scanResult = await client.scan(scanResult.cursor, { MATCH: '*11*' });
console.log(scanResult.cursor, scanResult.keys);

scanResult = await client.scan(scanResult.cursor, { MATCH: '*11*' });
console.log(scanResult.cursor, scanResult.keys);

scanResult = await client.scan(scanResult.cursor, { MATCH: '*11*', COUNT: 1000 });
console.log(scanResult.cursor, scanResult.keys);

cursor, key = r.scan(cursor=0, match='*11*')
print(cursor, key)

cursor, key = r.scan(cursor, match='*11*')
print(cursor, key)

cursor, key = r.scan(cursor, match='*11*')
print(cursor, key)

cursor, key = r.scan(cursor, match='*11*')
print(cursor, key)

cursor, keys = r.scan(cursor, match='*11*', count=1000)
print(cursor, keys)

// Note: Rust redis client scan_match returns an iterator, not cursor-based
        // This simulates the Python cursor-based output but uses the available API
        let keys = match r.scan_match("*11*").await {
            Ok(iter) => {
                let keys: Vec<Result<String, _>> = iter.collect().await;
                keys.into_iter().filter_map(|r| r.ok()).collect::<Vec<String>>()
            },
            Err(e) => {
                println!("Error scanning keys: {e}");
                return;
            }
        };

// Note: Rust redis client scan_match returns an iterator, not cursor-based
        // This simulates the Python cursor-based output but uses the available API
        match r.scan_match("*11*") {
            Ok(iter) => {
                let keys: Vec<String> = iter.filter_map(|r| r.ok()).collect();
            },
            Err(e) => {
                println!("Error scanning keys: {e}");
                return;
            }
        }

> GEOADD geokey 0 0 value
(integer) 1
> ZADD zkey 1000 value
(integer) 1
> TYPE geokey
zset
> TYPE zkey
zset
> SCAN 0 TYPE zset
1) "0"
2) 1) "geokey"
   2) "zkey"

const scan3Res1 = await client.geoAdd('geokey', { longitude: 0, latitude: 0, member: 'value' });
console.log(scan3Res1); // 1

const scan3Res2 = await client.zAdd('zkey', [{ score: 1000, value: 'value' }]);
console.log(scan3Res2); // 1

const scan3Res3 = await client.type('geokey');
console.log(scan3Res3); // zset

const scan3Res4 = await client.type('zkey');
console.log(scan3Res4); // zset

const scan3Res5 = await client.scan('0', { TYPE: 'zset' });
console.log(scan3Res5.keys); // ['zkey', 'geokey']

res = r.geoadd("geokey", (0, 0, "value"))
print(res)
# >>> 1

res = r.zadd("zkey", {"value": 1000})
print(res)
# >>> 1

res = r.type("geokey")
print(res)
# >>> zset

res = r.type("zkey")
print(res)
# >>> zset

cursor, keys = r.scan(cursor=0, _type="zset")
print(keys)
# >>> ['zkey', 'geokey']

match r.geo_add("geokey", &[(0.0, 0.0, "value")]).await {
            Ok(res) => {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            },
            Err(e) => {
                println!("Error adding geo location: {e}");
                return;
            }
        }

        match r.zadd("zkey", "value", 1000).await {
            Ok(res) => {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            },
            Err(e) => {
                println!("Error adding to sorted set: {e}");
                return;
            }
        }

        match r.key_type::<&str, redis::ValueType>("geokey").await {
            Ok(res) => {
                println!("{res:?}");    // >>> zset
            },
            Err(e) => {
                println!("Error getting key type: {e}");
                return;
            }
        }

        match r.key_type::<&str, redis::ValueType>("zkey").await {
            Ok(res) => {
                println!("{res:?}");    // >>> zset
            },
            Err(e) => {
                println!("Error getting key type: {e}");
                return;
            }
        }

        // Note: Rust redis client doesn't support scan by type directly
        // We'll manually check the types of our known keys
        let mut zset_keys = Vec::new();
        for key in &["geokey", "zkey"] {
            match r.key_type::<&str, redis::ValueType>(key).await {
                Ok(key_type) => {
                    if format!("{key_type:?}") == "ZSet" {
                        zset_keys.push(key.to_string());
                    }
                },
                Err(_) => {},
            }
        }
        println!("{:?}", zset_keys);    // >>> ["zkey", "geokey"]

match r.geo_add("geokey", &[(0.0, 0.0, "value")]) {
            Ok(res) => {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            },
            Err(e) => {
                println!("Error adding geo location: {e}");
                return;
            }
        }

        match r.zadd("zkey", "value", 1000) {
            Ok(res) => {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            },
            Err(e) => {
                println!("Error adding to sorted set: {e}");
                return;
            }
        }

        match r.key_type::<&str, redis::ValueType>("geokey") {
            Ok(res) => {
                println!("{res:?}");    // >>> zset
            },
            Err(e) => {
                println!("Error getting key type: {e}");
                return;
            }
        }

        match r.key_type::<&str, redis::ValueType>("zkey") {
            Ok(res) => {
                println!("{res:?}");    // >>> zset
            },
            Err(e) => {
                println!("Error getting key type: {e}");
                return;
            }
        }

        // Note: Rust redis client doesn't support scan by type directly
        // We'll manually check the types of our known keys
        let mut zset_keys = Vec::new();
        for key in &["geokey", "zkey"] {
            match r.key_type::<&str, redis::ValueType>(key) {
                Ok(key_type) => {
                    if format!("{key_type:?}") == "ZSet" {
                        zset_keys.push(key.to_string());
                    }
                },
                Err(_) => {},
            }
        }
        println!("{:?}", zset_keys);    // >>> ["zkey", "geokey"]

> HSET myhash a 1 b 2
OK
> HSCAN myhash 0
1) "0"
2) 1) "a"
   2) "1"
   3) "b"
   4) "2"
> HSCAN myhash 0 NOVALUES
1) "0"
2) 1) "a"
   2) "b"

const scan4Res1 = await client.hSet('myhash', { a: 1, b: 2 });
console.log(scan4Res1); // 2

const scan4Res2 = await client.hScan('myhash', '0');
console.log(scan4Res2.entries); // [{field: 'a', value: '1'}, {field: 'b', value: '2'}]

const scan4Res3 = await client.hScan('myhash', '0', { COUNT: 10 });
const items = scan4Res3.entries.map((item) => item.field)
console.log(items); // ['a', 'b']

res = r.hset("myhash", mapping={"a": 1, "b": 2})
print(res)
# >>> 2

cursor, keys = r.hscan("myhash", 0)
print(keys)
# >>> {'a': '1', 'b': '2'}

cursor, keys = r.hscan("myhash", 0, no_values=True)
print(keys)
# >>> ['a', 'b']

match r.hset("myhash", "a", "1").await {
            Ok(res) => {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            },
            Err(e) => {
                println!("Error setting hash field: {e}");
                return;
            }
        }

        match r.hset("myhash", "b", "2").await {
            Ok(res) => {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            },
            Err(e) => {
                println!("Error setting hash fields: {e}");
                return;
            }
        }

        let fields = match r.hscan("myhash").await {
            Ok(iter) => {
                let items: Vec<Result<(String, String), _>> = iter.collect().await;
                items.into_iter().filter_map(|r| r.ok()).collect::<std::collections::HashMap<String, String>>()
            },
            Err(e) => {
                println!("Error scanning hash: {e}");
                return;
            }
        };

        println!("{fields:?}");    // >>> {"a": "1", "b": "2"}

        // Scan hash keys only (no values)
        match r.hkeys("myhash").await {
            Ok(keys) => {
                let keys: Vec<String> = keys;
                println!("{keys:?}");    // >>> ["a", "b"]
            },
            Err(e) => {
                println!("Error getting hash keys: {e}");
                return;
            }
        }

match r.hset("myhash", "a", "1") {
            Ok(res) => {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            },
            Err(e) => {
                println!("Error setting hash field: {e}");
                return;
            }
        }

        match r.hset("myhash", "b", "2") {
            Ok(res) => {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            },
            Err(e) => {
                println!("Error setting hash fields: {e}");
                return;
            }
        }

        match r.hscan("myhash") {
            Ok(iter) => {
                let fields: std::collections::HashMap<String, String> = iter.filter_map(|r| r.ok()).collect();
                println!("{fields:?}");    // >>> {"a": "1", "b": "2"}
            },
            Err(e) => {
                println!("Error scanning hash: {e}");
                return;
            }
        }

        // Scan hash keys only (no values)
        match r.hkeys("myhash") {
            Ok(keys) => {
                let keys: Vec<String> = keys;
                println!("{keys:?}");    // >>> ["a", "b"]
            },
            Err(e) => {
                println!("Error getting hash keys: {e}");
                return;
            }
        }


SCARD

Summary: Returns the number of members in a set.

Overview

Returns the set cardinality (number of elements) of the set stored at `key`.

Examples

SADD myset "Hello"
SADD myset "World"
SCARD myset

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): the cardinality (number of elements) of the set, or `0` if the key does not exist.

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): The cardinality (number of elements) of the set, or 0 if the key does not exist.


SCRIPT

Summary: A container for Lua scripts management commands.

Content

This is a container command for script management commands.

To see the list of available commands you can call [`SCRIPT HELP`]().


SCRIPT DEBUG

Summary: Sets the debug mode of server-side Lua scripts.

Overview

Set the debug mode for subsequent scripts executed with [`EVAL`](). Redis includes a
complete Lua debugger, codename LDB, that can be used to make the task of
writing complex scripts much simpler. In debug mode Redis acts as a remote
debugging server and a client, such as `redis-cli`, can execute scripts step by
step, set breakpoints, inspect variables and more - for additional information
about LDB refer to the [Redis Lua debugger]() page.

**Important note:** avoid debugging Lua scripts using your Redis production
server. Use a development server instead.

LDB can be enabled in one of two modes: asynchronous or synchronous. In
asynchronous mode the server creates a forked debugging session that does not
block and all changes to the data are **rolled back** after the session
finishes, so debugging can be restarted using the same initial state. The
alternative synchronous debug mode blocks the server while the debugging session
is active and retains all changes to the data set once it ends.

* `YES`. Enable non-blocking asynchronous debugging of Lua scripts (changes are discarded).
* `SYNC`. Enable blocking synchronous debugging of Lua scripts (saves changes to data).
* `NO`. Disables scripts debug mode.

For more information about [`EVAL`]() scripts please refer to [Introduction to Eval Scripts]().

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ❌ Standard
<nobr>❌ Active-Active</nobr> | ❌ Standard
<nobr>❌ Active-Active</nobr> |  |

Return information

**RESP2:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): `OK`.

**RESP3:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): `OK`.


SCRIPT EXISTS

Summary: Determines whether server-side Lua scripts exist in the script cache.

Overview

Returns information about the existence of the scripts in the script cache.

This command accepts one or more SHA1 digests and returns a list of ones or
zeros to signal if the scripts are already defined or not inside the script
cache.
This can be useful before a pipelining operation to ensure that scripts are
loaded (and if not, to load them using [`SCRIPT LOAD`]()) so that the pipelining
operation can be performed solely using [`EVALSHA`]() instead of [`EVAL`]() to save
bandwidth.

For more information about [`EVAL`]() scripts please refer to [Introduction to Eval Scripts]().

Return information

**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): an array of integers that correspond to the specified SHA1 digest arguments.

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): an array of integers that correspond to the specified SHA1 digest arguments.


SCRIPT FLUSH

Summary: Removes all server-side Lua scripts from the script cache.

Overview

Flush the Lua scripts cache.

By default, `SCRIPT FLUSH` will synchronously flush the cache.
Starting with Redis 6.2, setting the **lazyfree-lazy-user-flush** configuration directive to "yes" changes the default flush mode to asynchronous.

It is possible to use one of the following modifiers to dictate the flushing mode explicitly:

* `ASYNC`: flushes the cache asynchronously
* `SYNC`: flushes the cache synchronously

For more information about [`EVAL`]() scripts please refer to [Introduction to Eval Scripts]().

Behavior change history

*   `>= 6.2.0`: Default flush behavior now configurable by the **lazyfree-lazy-user-flush** configuration directive.

Return information


SCRIPT HELP

Summary: Returns helpful text about the different subcommands.

Overview

The `SCRIPT HELP` command returns a helpful text describing the different subcommands.

Return information

**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): a list of sub-commands and their descriptions.

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): a list of sub-commands and their descriptions.


SCRIPT KILL

Summary: Terminates a server-side Lua script during execution.

Overview

Kills the currently executing [`EVAL`]() script, assuming no write operation was yet
performed by the script.

This command is mainly useful to kill a script that is running for too much
time(for instance, because it entered an infinite loop because of a bug).
The script will be killed, and the client currently blocked into EVAL will see
the command returning with an error.

If the script has already performed write operations, it can not be killed in this
way because it would violate Lua's script atomicity contract.
In such a case, only `SHUTDOWN NOSAVE` can kill the script, killing
the Redis process in a hard way and preventing it from persisting with half-written
information.

For more information about [`EVAL`]() scripts please refer to [Introduction to Eval Scripts]().

Return information


SCRIPT LOAD

Summary: Loads a server-side Lua script to the script cache.

Overview

Load a script into the scripts cache, without executing it.
After the specified command is loaded into the script cache it will be callable
using [`EVALSHA`]() with the correct SHA1 digest of the script, exactly like after
the first successful invocation of [`EVAL`]().

The script is guaranteed to stay in the script cache forever (unless `SCRIPT
FLUSH` is called).

The command works in the same way even if the script was already present in the
script cache.

For more information about [`EVAL`]() scripts please refer to [Introduction to Eval Scripts]().

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
<nobr>✅ Active-Active</nobr> | ✅ Standard
<nobr>✅ Active-Active</nobr> |  |

Return information

**RESP2:**

[Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): the SHA1 digest of the script added into the script cache.

**RESP3:**

[Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): the SHA1 digest of the script added into the script cache.


SDIFF

Summary: Returns the difference of multiple sets.

Overview

This command's behavior varies in clustered Redis environments. See the [multi-key operations]() page for more information.

Returns the members of the set resulting from the difference between the first
set and all the successive sets.

For example:

[code example]

Keys that do not exist are considered to be empty sets.

Examples

SADD key1 "a"
SADD key1 "b"
SADD key1 "c"
SADD key2 "c"
SADD key2 "d"
SADD key2 "e"
SDIFF key1 key2

Return information

**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): a list with members of the resulting set.

**RESP3:**

[Set reply](../../develop/reference/protocol-spec#sets): a set with the members of the resulting set.

key1 = {a,b,c,d}
key2 = {c}
key3 = {a,c,e}
SDIFF key1 key2 key3 = {b,d}


SDIFFSTORE

Summary: Stores the difference of multiple sets in a key.

Overview

This command's behavior varies in clustered Redis environments. See the [multi-key operations]() page for more information.

This command is equal to [`SDIFF`](), but instead of returning the resulting set, it
is stored in `destination`.

If `destination` already exists, it is overwritten.

Examples

SADD key1 "a"
SADD key1 "b"
SADD key1 "c"
SADD key2 "c"
SADD key2 "d"
SADD key2 "e"
SDIFFSTORE key key1 key2
SMEMBERS key

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): the number of elements in the resulting set.

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): the number of elements in the resulting set.


SELECT

Summary: Changes the selected database.

Overview

Select the Redis logical database having the specified zero-based numeric index.
New connections always use the database 0.

Selectable Redis databases are a form of namespacing: all databases are still persisted in the same RDB / AOF file. However different databases can have keys with the same name, and commands like [`FLUSHDB`](), [`SWAPDB`]() or [`RANDOMKEY`]() work on specific databases.

In practical terms, Redis databases should be used to separate different keys belonging to the same application (if needed), and not to use a single Redis instance for multiple unrelated applications.

When using Redis Cluster, the `SELECT` command cannot be used, since Redis Cluster only supports database zero. In the case of a Redis Cluster, having multiple databases would be useless and an unnecessary source of complexity. Commands operating atomically on a single database would not be possible with the Redis Cluster design and goals.

Since the currently selected database is a property of the connection, clients should track the currently selected database and re-select it on reconnection. While there is no command in order to query the selected database in the current connection, the [`CLIENT LIST`]() output shows, for each client, the currently selected database.

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ❌ Standard
<nobr>❌ Active-Active</nobr> | ❌ Standard
<nobr>❌ Active-Active</nobr> | Redis Software does not support shared databases due to potential negative performance impacts and blocks any related commands. The `SELECT` command is supported solely for compatibility with Redis Open Source but does not perform any operations in Redis Software. |

Return information

**RESP2:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): `OK`.

**RESP3:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): `OK`.


SET

Summary: Sets the string value of a key, ignoring its type. The key is created if it doesn't exist.

Options

The `SET` command supports a set of options that modify its behavior:

* `NX` -- Only set the key if it does not already exist.
* `XX` -- Only set the key if it already exists.
* `IFEQ ifeq-value` -- Set the key’s value and expiration only if its current value is equal to `ifeq-value`. If the key doesn’t exist, it won’t be created.
* `IFNE ifne-value` -- Set the key’s value and expiration only if its current value is not equal to `ifne-value`. If the key doesn’t exist, it will be created.
* `IFDEQ ifeq-digest` -- Set the key’s value and expiration only if the hash digest of its current value is equal to `ifeq-digest`. If the key doesn’t exist, it won’t be created. See the [Hash Digest](#hash-digest) section below for more information.
* `IFDNE ifne-digest` -- Set the key’s value and expiration only if the hash digest of its current value is not equal to `ifne-digest`. If the key doesn’t exist, it will be created. See the [Hash Digest](#hash-digest) section below for more information.
* `GET` -- Return the old string stored at key, or nil if key did not exist. An error is returned and `SET` aborted if the value stored at key is not a string.
* `EX` *seconds* -- Set the specified expire time, in seconds (a positive integer).
* `PX` *milliseconds* -- Set the specified expire time, in milliseconds (a positive integer).
* `EXAT` *timestamp-seconds* -- Set the specified Unix time at which the key will expire, in seconds (a positive integer).
* `PXAT` *timestamp-milliseconds* -- Set the specified Unix time at which the key will expire, in milliseconds (a positive integer).
* `KEEPTTL` -- Retain the time to live associated with the key.

Note: Since the `SET` command options can replace [`SETNX`](), [`SETEX`](), [`PSETEX`](), [`GETSET`](), it is possible that in future versions of Redis these commands will be deprecated and finally removed.

Hash Digest

A hash digest is a fixed-size numerical representation of a string value, computed using the XXH3 hash algorithm. Redis uses this hash digest for efficient comparison operations without needing to compare the full string content. You can retrieve a key's hash digest using the [`DIGEST`]() command, which returns it as a hexadecimal string that you can use with the `IFDEQ` and `IFDNE` options, and also the [`DELEX`]() command's `IFDEQ` and `IFDNE` options.

Examples

SET mykey "Hello"
GET mykey

SET anotherkey "will expire in a minute" EX 60

Code examples

#### Code Examples

Foundational: Set the string value of a key using SET (creates key if needed, overwrites existing value, supports expiration options)

**Difficulty:** Beginner

**Available in:** Python, JavaScript (Node.js), Java (Synchronous - Jedis), Go, C# (Synchronous)

**Python:**

[code example]

**JavaScript (Node.js):**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**Go:**

[code example]

**C# (Synchronous):**

[code example]

Patterns

**Note:** The following pattern is discouraged in favor of [the Redlock algorithm]() which is only a bit more complex to implement, but offers better guarantees and is fault tolerant.

The command `SET resource-name anystring NX EX max-lock-time` is a simple way to implement a locking system with Redis.

A client can acquire the lock if the above command returns `OK` (or retry after some time if the command returns Nil), and remove the lock just using [`DEL`]().

The lock will be auto-released after the expire time is reached.

It is possible to make this system more robust modifying the unlock schema as follows:

* Instead of setting a fixed string, set a non-guessable large random string, called token.
* Instead of releasing the lock with [`DEL`](), send a script that only removes the key if the value matches.

This avoids that a client will try to release the lock after the expire time deleting the key created by another client that acquired the lock later.

An example of unlock script would be similar to the following:

    if redis.call("get",KEYS[1]) == ARGV[1]
    then
        return redis.call("del",KEYS[1])
    else
        return 0
    end

The script should be called with `EVAL ...script... 1 resource-name token-value`

Return information

**RESP2:**

* If `GET` was not specified, one of the following:
  * [Null bulk string reply](../../develop/reference/protocol-spec#bulk-strings) in the following two cases.
    * The key doesn’t exist and `XX/IFEQ/IFDEQ` was specified. The key was not created.
    * The key exists, and `NX` was specified or a specified `IFEQ/IFNE/IFDEQ/IFDNE` condition is false. The key was not set.
  * [Simple string reply](../../develop/reference/protocol-spec#simple-strings): `OK`: The key was set.
* If `GET` was specified, one of the following:
  * [Null bulk string reply](../../develop/reference/protocol-spec#bulk-strings): The key didn't exist before the `SET` operation, whether the key was created of not.
  * [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): The previous value of the key, whether the key was set or not.

**RESP3:**

* If `GET` was not specified, one of the following:
  * [Null reply](../../develop/reference/protocol-spec#nulls) in the following two cases.
    * The key doesn’t exist and `XX/IFEQ/IFDEQ` was specified. The key was not created.
    * The key exists, and `NX` was specified or a specified `IFEQ/IFNE/IFDEQ/IFDNE` condition is false. The key was not set.
  * [Simple string reply](../../develop/reference/protocol-spec#simple-strings): `OK`: The key was set.
* If `GET` was specified, one of the following:
  * [Null reply](../../develop/reference/protocol-spec#nulls): The key didn't exist before the `SET` operation, whether the key was created of not.
  * [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): The previous value of the key, whether the key was set or not.

"""
Code samples for data structure store quickstart pages:
    https://redis.io/docs/latest/develop/get-started/data-store/
"""

import redis

r = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True)

res = r.set("bike:1", "Process 134")
print(res)
# >>> True

res = r.get("bike:1")
print(res)
# >>> "Process 134"

import { createClient } from 'redis';

const client = createClient();

client.on('error', err => console.log('Redis Client Error', err));

await client.connect().catch(console.error);

await client.set('bike:1', 'Process 134');
const value = await client.get('bike:1');
console.log(value);
// returns 'Process 134'

await client.close();

package io.redis.examples;

import redis.clients.jedis.RedisClient;

public class SetGetExample {

  public void run() {

    RedisClient jedis = RedisClient.create("redis://localhost:6379");

    String status = jedis.set("bike:1", "Process 134");

    if ("OK".equals(status)) System.out.println("Successfully added a bike.");

    String value = jedis.get("bike:1");

    if (value != null) System.out.println("The name of the bike is: " + value + ".");

    jedis.close();
  }
}

package example_commands_test

import (
	"context"
	"fmt"

	"github.com/redis/go-redis/v9"
)

func ExampleClient_Set_and_get() {
	ctx := context.Background()

	rdb := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password docs
		DB:       0,  // use default DB
	})

	err := rdb.Set(ctx, "bike:1", "Process 134", 0).Err()
	if err != nil {
		panic(err)
	}

	fmt.Println("OK")

	value, err := rdb.Get(ctx, "bike:1").Result()
	if err != nil {
		panic(err)
	}
	fmt.Printf("The name of the bike is %s", value)

}

using NRedisStack.Tests;
using StackExchange.Redis;

public class SetGetExample
{
    public void Run()
    {
        var muxer = ConnectionMultiplexer.Connect("localhost:6379");
        var db = muxer.GetDatabase();

        bool status = db.StringSet("bike:1", "Process 134");

        if (status)
            Console.WriteLine("Successfully added a bike.");

        var value = db.StringGet("bike:1");

        if (value.HasValue)
            Console.WriteLine("The name of the bike is: " + value + ".");

    }
}