TS.RANGE

Summary: Query a range in forward direction

Overview

Query a range in forward direction. Starting from Redis 8.6, NaN values are included in raw measurement reports (queries without aggregation).

[Examples](#examples)

Required arguments

key

is the key name for the time series.

fromTimestamp

is start timestamp for the range query (integer Unix timestamp in milliseconds) or `-` to denote the timestamp of the earliest sample in the time series.

toTimestamp

is end timestamp for the range query (integer Unix timestamp in milliseconds) or `+` to denote the timestamp of the latest sample in the time series.

<note>Note:    When the time series is a compaction, the last compacted value may aggregate raw values with timestamp beyond `toTimestamp`. That is because `toTimestamp` only limits the timestamp of the compacted value, which is the start time of the raw bucket that was compacted.</note>

Optional arguments

LATEST (since RedisTimeSeries 1.8)

is used when a time series is a compaction. With `LATEST`, TS.RANGE also reports the compacted value of the latest, possibly partial, bucket, given that this bucket's start time falls within `[fromTimestamp, toTimestamp]`. Without `LATEST`, TS.RANGE does not report the latest, possibly partial, bucket. When a time series is not a compaction, `LATEST` is ignored.

The data in the latest bucket of a compaction is possibly partial. A bucket is _closed_ and compacted only upon arrival of a new sample that _opens_ a new _latest_ bucket. There are cases, however, when the compacted value of the latest, possibly partial, bucket is also required. In such a case, use `LATEST`.

FILTER_BY_TS ts... (since RedisTimeSeries 1.6)

filters samples by a list of specific timestamps. A sample passes the filter if its exact timestamp is specified and falls within `[fromTimestamp, toTimestamp]`.

When used together with `AGGREGATION`: samples are filtered before being aggregated.

FILTER_BY_VALUE min max (since RedisTimeSeries 1.6)

filters samples by minimum and maximum values. `min` and `max` cannot be NaN values.

When used together with `AGGREGATION`: samples are filtered before being aggregated.

COUNT count

When used without `AGGREGATION`: limits the number of reported samples.

When used together with `AGGREGATION`: limits the number of reported buckets.

ALIGN align (since RedisTimeSeries 1.6)

is a time bucket alignment control for `AGGREGATION`. It controls the time bucket timestamps by changing the reference timestamp on which a bucket is defined.

`align` values include:

 - `start` or `-`: The reference timestamp will be the query start interval time (`fromTimestamp`) which can't be `-`
 - `end` or `+`: The reference timestamp will be the query end interval time (`toTimestamp`) which can't be `+`
 - A specific timestamp: align the reference timestamp to a specific time

<note>Note: When not provided, alignment is set to `0`.</note>

AGGREGATION aggregator bucketDuration

aggregates samples into time buckets, where:

  - `aggregator` takes one of the following aggregation types:

    | `aggregator` | Description                                                     |
    | ------------ | --------------------------------------------------------------- |
    | `avg`        | Arithmetic mean of all non-NaN values                           |
    | `sum`        | Sum of all non-NaN values                                       |
    | `min`        | Minimum non-NaN value                                           |
    | `max`        | Maximum non-NaN value                                           |
    | `range`      | Difference between the maximum and the minimum non-NaN values   |
    | `count`      | Number of non-NaN values                                        |
    | `countNaN`   | Number of NaN values (since Redis 8.6)                          |
    | `countAll`   | Number of values, including NaN and non-NaN (since Redis 8.6)   |
    | `first`      | The non-NaN value with the lowest timestamp in the bucket       |
    | `last`       | The non-NaN value with the highest timestamp in the bucket      |
    | `std.p`      | Population standard deviation of the non-NaN values             |
    | `std.s`      | Sample standard deviation of the non-NaN values                 |
    | `var.p`      | Population variance of the non-NaN values                       |
    | `var.s`      | Sample variance of the non-NaN values                           |
    | `twa`        | Time-weighted average over the bucket's timeframe (ignores NaN values) (since RedisTimeSeries 1.8) |

  - `bucketDuration` is duration of each bucket, in milliseconds.

  Without `ALIGN`, bucket start times are multiples of `bucketDuration`.

  With `ALIGN align`, bucket start times are multiples of `bucketDuration` with remainder `align % bucketDuration`.

  The first bucket start time is less than or equal to `fromTimestamp`.

[BUCKETTIMESTAMP bt] (since RedisTimeSeries 1.8)

controls how bucket timestamps are reported.

| `bt`             | Timestamp reported for each bucket                            |
| ---------------- | ------------------------------------------------------------- |
| `-` or `start`   | the bucket's start time (default)                             |
| `+` or `end`     | the bucket's end time                                         |
| `~` or `mid`     | the bucket's mid time (rounded down if not an integer)        |

[EMPTY] (since RedisTimeSeries 1.8)

is a flag, which, when specified, reports aggregations also for empty buckets.

| `aggregator`         | Value reported for each empty bucket |
| -------------------- | ------------------------------------ |
| `sum`, `count`       | `0`                                  |
| `last`               | The value of the last sample before the bucket's start. `NaN` when no such sample. |
| `twa`                | Average value over the bucket's timeframe based on linear interpolation of the last sample before the bucket's start and the first sample after the bucket's end. `NaN` when no such samples. |
| `min`, `max`, `range`, `avg`, `first`, `std.p`, `std.s` | `NaN` |

Regardless of the values of `fromTimestamp` and `toTimestamp`, no data is reported for buckets that end before the earliest sample or begin after the latest sample in the time series.

Complexity

TS.RANGE complexity can be improved in the future by using binary search to find the start of the range, which makes this `O(Log(n/m)+k*m)`.
But, because `m` is small, you can disregard it and look at the operation as `O(Log(n)+k)`.

Examples

Filter results by timestamp or sample value

Consider a metric where acceptable values are between -100 and 100, and the value 9999 is used as an indication of bad measurement.

127.0.0.1:6379> TS.CREATE temp:TLV LABELS type temp location TLV
OK
127.0.0.1:6379> TS.MADD temp:TLV 1000 30 temp:TLV 1010 35 temp:TLV 1020 9999 temp:TLV 1030 40
1) (integer) 1000
2) (integer) 1010
3) (integer) 1020
4) (integer) 1030

Now, retrieve all values except out-of-range values.

TS.RANGE temp:TLV - + FILTER_BY_VALUE -100 100
1) 1) (integer) 1000
   2) 30
2) 1) (integer) 1010
   2) 35
3) 1) (integer) 1030
   2) 40

Now, retrieve the average value, while ignoring out-of-range values.

TS.RANGE temp:TLV - + FILTER_BY_VALUE -100 100 AGGREGATION avg 1000
1) 1) (integer) 1000
   2) 35

Align aggregation buckets

To demonstrate alignment, let’s create a stock and add prices at nine different timestamps.

127.0.0.1:6379> TS.CREATE stock:A LABELS type stock name A
OK
127.0.0.1:6379> TS.MADD stock:A 1000 100 stock:A 1010 110 stock:A 1020 120
1) (integer) 1000
2) (integer) 1010
3) (integer) 1020
127.0.0.1:6379> TS.MADD stock:A 2000 200 stock:A 2010 210 stock:A 2020 220
1) (integer) 2000
2) (integer) 2010
3) (integer) 2020
127.0.0.1:6379> TS.MADD stock:A 3000 300 stock:A 3010 310 stock:A 3020 320
1) (integer) 3000
2) (integer) 3010
3) (integer) 3020

Next, aggregate without using `ALIGN`, defaulting to alignment 0.

127.0.0.1:6379> TS.RANGE stock:A - + AGGREGATION min 20
1) 1) (integer) 1000
   2) 100
2) 1) (integer) 1020
   2) 120
3) 1) (integer) 2000
   2) 200
4) 1) (integer) 2020
   2) 220
5) 1) (integer) 3000
   2) 300
6) 1) (integer) 3020
   2) 320

And now set `ALIGN` to 10 to have a bucket start at time 10, and align all the buckets with a 20 milliseconds duration.

127.0.0.1:6379> TS.RANGE stock:A - + ALIGN 10 AGGREGATION min 20
1) 1) (integer) 990
   2) 100
2) 1) (integer) 1010
   2) 110
3) 1) (integer) 1990
   2) 200
4) 1) (integer) 2010
   2) 210
5) 1) (integer) 2990
   2) 300
6) 1) (integer) 3010
   2) 310

When the start timestamp for the range query is explicitly stated (not `-`), you can set `ALIGN` to that time by setting align to `-` or to `start`.

127.0.0.1:6379> TS.RANGE stock:A 5 + ALIGN - AGGREGATION min 20
1) 1) (integer) 985
   2) 100
2) 1) (integer) 1005
   2) 110
3) 1) (integer) 1985
   2) 200
4) 1) (integer) 2005
   2) 210
5) 1) (integer) 2985
   2) 300
6) 1) (integer) 3005
   2) 310

Similarly, when the end timestamp for the range query is explicitly stated, you can set `ALIGN` to that time by setting align to `+` or to `end`.

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Supported
 | ✅ Flexible & Annual
✅ Free & Fixed</nobr> |  |

Return information

**RESP2:**

One of the following:
* [Array reply]() of ([Integer reply](), [Simple string reply]()) pairs representing (timestamp, value).
* [Simple error reply]() in these cases: invalid filter value, wrong key type, key does not exist, etc.

**RESP3:**

One of the following:
* [Array reply]() of ([Integer reply](), [Double reply]()) pairs representing (timestamp, value).
* [Simple error reply]() in these cases: invalid filter value, wrong key type, key does not exist, etc.

See also

[`TS.MRANGE`]() | [`TS.REVRANGE`]() | [`TS.MREVRANGE`]()

Related topics

[RedisTimeSeries]()


TS.REVRANGE

Summary: Query a range in reverse direction

Overview

Query a range in reverse direction. Starting from Redis 8.6, NaN values are included in raw measurement reports (queries without aggregation).

[Examples](#examples)

Required arguments

key

is the key name for the time series.

fromTimestamp

is start timestamp for the range query (integer Unix timestamp in milliseconds) or `-` to denote the timestamp of the earliest sample in the time series.

toTimestamp

is end timestamp for the range query (integer Unix timestamp in milliseconds) or `+` to denote the timestamp of the latest sample in the time series.

<note>Note:  When the time series is a compaction, the last compacted value may aggregate raw values with timestamp beyond `toTimestamp`. That is because `toTimestamp` limits only the timestamp of the compacted value, which is the start time of the raw bucket that was compacted.</note>

Optional arguments

LATEST (since RedisTimeSeries 1.8)

is used when a time series is a compaction. With `LATEST`, TS.REVRANGE also reports the compacted value of the latest, possibly partial, bucket, given that this bucket's start time falls within `[fromTimestamp, toTimestamp]`. Without `LATEST`, TS.REVRANGE does not report the latest, possibly partial, bucket. When a time series is not a compaction, `LATEST` is ignored.

The data in the latest bucket of a compaction is possibly partial. A bucket is _closed_ and compacted only upon arrival of a new sample that _opens_ a new _latest_ bucket. There are cases, however, when the compacted value of the latest, possibly partial, bucket is also required. In such a case, use `LATEST`.

FILTER_BY_TS ts... (since RedisTimeSeries 1.6)

filters samples by a list of specific timestamps. A sample passes the filter if its exact timestamp is specified and falls within `[fromTimestamp, toTimestamp]`.

When used together with `AGGREGATION`: samples are filtered before being aggregated.

FILTER_BY_VALUE min max (since RedisTimeSeries 1.6)

filters samples by minimum and maximum values. `min` and `max` cannot be NaN values.

When used together with `AGGREGATION`: samples are filtered before being aggregated.

COUNT count

When used without `AGGREGATION`: limits the number of reported samples.

When used together with `AGGREGATION`: limits the number of reported buckets.

ALIGN align (since RedisTimeSeries 1.6)

is a time bucket alignment control for `AGGREGATION`. It controls the time bucket timestamps by changing the reference timestamp on which a bucket is defined.
Values include:

 - `start` or `-`: The reference timestamp will be the query start interval time (`fromTimestamp`) which can't be `-`
 - `end` or `+`: The reference timestamp will be the query end interval time (`toTimestamp`) which can't be `+`
 - A specific timestamp: align the reference timestamp to a specific time

<note>NOTE: When not provided, alignment is set to `0`.</note>

AGGREGATION aggregator bucketDuration
aggregates samples into time buckets, where:

  - `aggregator` takes one of the following aggregation types:

    | `aggregator` | Description                                                     |
    | ------------ | --------------------------------------------------------------- |
    | `avg`        | Arithmetic mean of all non-NaN values                           |
    | `sum`        | Sum of all non-NaN values                                       |
    | `min`        | Minimum non-NaN value                                           |
    | `max`        | Maximum non-NaN value                                           |
    | `range`      | Difference between the maximum and the minimum non-NaN values   |
    | `count`      | Number of non-NaN values                                        |
    | `countNaN`   | Number of NaN values (since Redis 8.6)                          |
    | `countAll`   | Number of values, including NaN and non-NaN (since Redis 8.6)   |
    | `first`      | The non-NaN value with the lowest timestamp in the bucket       |
    | `last`       | The non-NaN value with the highest timestamp in the bucket      |
    | `std.p`      | Population standard deviation of the non-NaN values             |
    | `std.s`      | Sample standard deviation of the non-NaN values                 |
    | `var.p`      | Population variance of the non-NaN values                       |
    | `var.s`      | Sample variance of the non-NaN values                           |
    | `twa`        | Time-weighted average over the bucket's timeframe (ignores NaN values) (since RedisTimeSeries 1.8) |

  - `bucketDuration` is duration of each bucket, in milliseconds.

  Without `ALIGN`, bucket start times are multiples of `bucketDuration`.

  With `ALIGN align`, bucket start times are multiples of `bucketDuration` with remainder `align % bucketDuration`.

  The first bucket start time is less than or equal to `fromTimestamp`.

[BUCKETTIMESTAMP bt] (since RedisTimeSeries 1.8)

controls how bucket timestamps are reported.

| `bt`             | Timestamp reported for each bucket                            |
| ---------------- | ------------------------------------------------------------- |
| `-` or `start`   | the bucket's start time (default)                             |
| `+` or `end`     | the bucket's end time                                         |
| `~` or `mid`     | the bucket's mid time (rounded down if not an integer)        |

[EMPTY] (since RedisTimeSeries 1.8)
is a flag, which, when specified, reports aggregations also for empty buckets.

| `aggregator`         | Value reported for each empty bucket |
| -------------------- | ------------------------------------ |
| `sum`, `count`       | `0`                                  |
| `last`               | The value of the last sample before the bucket's start. `NaN` when no such sample. |
| `twa`                | Average value over the bucket's timeframe based on linear interpolation of the last sample before the bucket's start and the first sample after the bucket's end. `NaN` when no such samples. |
| `min`, `max`, `range`, `avg`, `first`, `std.p`, `std.s` | `NaN` |

Regardless of the values of `fromTimestamp` and `toTimestamp`, no data is reported for buckets that end before the earliest sample or begin after the latest sample in the time series.

Complexity

TS.REVRANGE complexity can be improved in the future by using binary search to find the start of the range, which makes this `O(Log(n/m)+k*m)`.
But, because `m` is small, you can disregard it and look at the operation as `O(Log(n)+k)`.

Examples

Filter results by timestamp or sample value

Consider a metric where acceptable values are between -100 and 100, and the value 9999 is used as an indication of bad measurement.

127.0.0.1:6379> TS.CREATE temp:TLV LABELS type temp location TLV
OK
127.0.0.1:6379> TS.MADD temp:TLV 1000 30 temp:TLV 1010 35 temp:TLV 1020 9999 temp:TLV 1030 40
1) (integer) 1000
2) (integer) 1010
3) (integer) 1020
4) (integer) 1030

Now, retrieve all values except out-of-range values.

TS.REVRANGE temp:TLV - + FILTER_BY_VALUE -100 100
1) 1) (integer) 1030
   2) 40
2) 1) (integer) 1010
   2) 35
3) 1) (integer) 1000
   2) 30

Now, retrieve the average value, while ignoring out-of-range values.

TS.REVRANGE temp:TLV - + FILTER_BY_VALUE -100 100 AGGREGATION avg 1000
1) 1) (integer) 1000
   2) 35

Align aggregation buckets

To demonstrate alignment, let’s create a stock and add prices at three different timestamps.

127.0.0.1:6379> TS.CREATE stock:A LABELS type stock name A
OK
127.0.0.1:6379> TS.MADD stock:A 1000 100 stock:A 1010 110 stock:A 1020 120
1) (integer) 1000
2) (integer) 1010
3) (integer) 1020
127.0.0.1:6379> TS.MADD stock:A 2000 200 stock:A 2010 210 stock:A 2020 220
1) (integer) 2000
2) (integer) 2010
3) (integer) 2020
127.0.0.1:6379> TS.MADD stock:A 3000 300 stock:A 3010 310 stock:A 3020 320
1) (integer) 3000
2) (integer) 3010
3) (integer) 3020

Next, aggregate without using `ALIGN`, defaulting to alignment 0.

127.0.0.1:6379> TS.REVRANGE stock:A - + AGGREGATION min 20
1) 1) (integer) 3020
   2) 320
2) 1) (integer) 3000
   2) 300
3) 1) (integer) 2020
   2) 220
4) 1) (integer) 2000
   2) 200
5) 1) (integer) 1020
   2) 120
6) 1) (integer) 1000
   2) 100

And now set `ALIGN` to 10 to have a bucket start at time 10, and align all the buckets with a 20 milliseconds duration.

127.0.0.1:6379> TS.REVRANGE stock:A - + ALIGN 10 AGGREGATION min 20
1) 1) (integer) 3010
   2) 310
2) 1) (integer) 2990
   2) 300
3) 1) (integer) 2010
   2) 210
4) 1) (integer) 1990
   2) 200
5) 1) (integer) 1010
   2) 110
6) 1) (integer) 990
   2) 100

When the start timestamp for the range query is explicitly stated (not `-`), you can set ALIGN to that time by setting align to `-` or to `start`.

127.0.0.1:6379> TS.REVRANGE stock:A 5 + ALIGN - AGGREGATION min 20
1) 1) (integer) 3005
   2) 310
2) 1) (integer) 2985
   2) 300
3) 1) (integer) 2005
   2) 210
4) 1) (integer) 1985
   2) 200
5) 1) (integer) 1005
   2) 110
6) 1) (integer) 985
   2) 100

Similarly, when the end timestamp for the range query is explicitly stated, you can set ALIGN to that time by setting align to `+` or to `end`.

Redis Software and Redis Cloud compatibility

Return information

**RESP2:**

One of the following:
* [Array reply]() of ([Integer reply](), [Simple string reply]()) pairs representing (timestamp, value) in reverse chronological order.
* [Simple error reply]() in these cases: invalid filter value, wrong key type, key does not exist, etc.

**RESP3:**

One of the following:
* [Array reply]() of ([Integer reply](), [Double reply]()) pairs representing (timestamp, value) in reverse chronological order.
* [Simple error reply]() in these cases: invalid filter value, wrong key type, key does not exist, etc.

See also

[`TS.RANGE`]() | [`TS.MRANGE`]() | [`TS.MREVRANGE`]()

Related topics

[RedisTimeSeries]()


TTL

Summary: Returns the expiration time in seconds of a key.

Examples

#### Code Examples

Foundational: Check remaining time-to-live of a key using TTL (returns seconds remaining, -1 if no expiry, -2 if key doesn't exist)

**Difficulty:** Beginner

**Commands:** SET, EXPIRE, TTL

**Complexity:**
- SET: O(1)
- EXPIRE: O(1)
- TTL: 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]

Give these commands a try in the interactive console:

SET mykey "Hello"
EXPIRE mykey 10
TTL mykey

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

Return information

**RESP2:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): TTL in seconds.
* [Integer reply](../../develop/reference/protocol-spec#integers): `-1` if the key exists but has no associated expiration.
* [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if the key does not exist.

**RESP3:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): TTL in seconds.
* [Integer reply](../../develop/reference/protocol-spec#integers): `-1` if the key exists but has no associated expiration.
* [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if the key does not exist.

> SET mykey "Hello"
"OK"
> EXPIRE mykey 10
(integer) 1
> TTL mykey
(integer) 10

#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;
}

bool ttlResult1 = db.StringSet("mykey", "Hello");
        Console.WriteLine(ttlResult1);  // >>> true

        bool ttlResult2 = db.KeyExpire("mykey", new TimeSpan(0, 0, 10));
        Console.WriteLine(ttlResult2);

        TimeSpan ttlResult3 = db.KeyTimeToLive("mykey") ?? TimeSpan.Zero;
        string ttlRes = Math.Round(ttlResult3.TotalSeconds).ToString();
        Console.WriteLine(Math.Round(ttlResult3.TotalSeconds)); // >>> 10

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();
        }
    }

}

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

const ttlRes1 = await client.set('mykey', 'Hello');
console.log(ttlRes1); // OK

const ttlRes2 = await client.expire('mykey', 10);
console.log(ttlRes2); // 1

const ttlRes3 = await client.ttl('mykey');
console.log(ttlRes3); // 10

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.set("mykey", "Hello")
print(res)
# >>> True

res = r.expire("mykey", 10)
print(res)
# >>> True

res = r.ttl("mykey")
print(res)
# >>> 10

if let Ok(res) = r.set("mykey", "Hello").await {
            let res: String = res;
            println!("{res}");    // >>> OK
        }

        match r.expire("mykey", 10).await {
            Ok(res) => {
                let res: bool = res;
                println!("{res}");    // >>> true
            },
            Err(e) => {
                println!("Error setting key expiration: {e}");
                return;
            }
        }

        match r.ttl("mykey").await {
            Ok(res) => {
                let res: i64 = res;
                println!("{res}");    // >>> 10
            },
            Err(e) => {
                println!("Error getting key TTL: {e}");
                return;
            }
        }

if let Ok(res) = r.set("mykey", "Hello") {
            let res: String = res;
            println!("{res}");    // >>> OK
        }

        match r.expire("mykey", 10) {
            Ok(res) => {
                let res: bool = res;
                println!("{res}");    // >>> true
            },
            Err(e) => {
                println!("Error setting key expiration: {e}");
                return;
            }
        }

        match r.ttl("mykey") {
            Ok(res) => {
                let res: i64 = res;
                println!("{res}");    // >>> 10
            },
            Err(e) => {
                println!("Error getting key TTL: {e}");
                return;
            }
        }


TYPE

Summary: Determines the type of value stored at a key.

Overview

Returns the string representation of the type of the value stored at `key`.
The different types that can be returned are: `string`, `list`, `set`, `zset`,
`hash`, `stream`, and `vectorset`.

Examples

SET key1 "value"
LPUSH key2 "value"
SADD key3 "value"
TYPE key1
TYPE key2
TYPE key3

Return information

**RESP2:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): the type of _key_, or `none` when _key_ doesn't exist.

**RESP3:**

[Simple string reply](../../develop/reference/protocol-spec#simple-strings): the type of _key_, or `none` when _key_ doesn't exist.


UNLINK

Summary: Asynchronously deletes one or more keys.

Overview

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

This command is very similar to [`DEL`](): it removes the specified keys.
Just like [`DEL`]() a key is ignored if it does not exist. However the command
performs the actual memory reclaiming in a different thread, so it is not
blocking, while [`DEL`]() is. This is where the command name comes from: the
command just **unlinks** the keys from the keyspace. The actual removal
will happen later asynchronously.

Examples

SET key1 "Hello"
SET key2 "World"
UNLINK key1 key2 key3

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): the number of keys that were unlinked.

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): the number of keys that were unlinked.


UNSUBSCRIBE

Summary: Stops listening to messages posted to channels.

Overview

Unsubscribes the client from the given channels, or from all of them if none is
given.

When no channels are specified, the client is unsubscribed from all the
previously subscribed channels.
In this case, a message for every unsubscribed channel will be sent to the
client.

Return information

**RESP2:**

When successful, this command doesn't return anything. Instead, for each channel, one message with the first element being the string `unsubscribe` is pushed as a confirmation that the command succeeded.

**RESP3:**

When successful, this command doesn't return anything. Instead, for each channel, one message with the first element being the string `unsubscribe` is pushed as a confirmation that the command succeeded.


UNWATCH

Summary: Forgets about watched keys of a transaction.

Overview

Flushes all the previously watched keys for a [transaction][tt].

[tt]: /develop/interact/transactions

If you call [`EXEC`]() or [`DISCARD`](), there's no need to manually call `UNWATCH`.

Return information

**RESP2:**

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

**RESP3:**

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


VADD

Summary: Add a new element to a vector set, or update its vector if it already exists.

Overview

Add a new element into the vector set specified by `key`. The vector can be provided as 32-bit floating point (`FP32`) blob of values, or as floating point numbers as strings, prefixed by the number of elements (3 in the example below):

[code example]

Required arguments

key

is the name of the key that will hold the vector set data.

FP32 vector or VALUES num vector

either a 32-bit floating point (FP32) blob of values or `num` floating point numbers as strings. When using the FP32 format, the blob must use little-endian encoding. On platforms with different endianness, you should either manually adjust the byte order or use the VALUES syntax instead.

element

is the name of the element that is being added to the vector set.

Optional arguments

REDUCE dim

implements random projection to reduce the dimensionality of the vector. The projection matrix is saved and reloaded along with the vector set. Please note that the REDUCE option must be passed immediately before the vector. For example,

[code example]

CAS

performs the operation partially using threads, in a check-and-set style. The neighbor candidates collection, which is slow, is performed in the background, while the command is executed in the main thread.

NOQUANT

in the first VADD call for a given key, NOQUANT forces the vector to be created without int8 quantization, which is otherwise the default.

BIN

forces the vector to use binary quantization instead of int8. This is much faster and uses less memory, but impacts the recall quality.

Q8

forces the vector to use signed 8-bit quantization. This is the default, and the option only exists to make sure to check at insertion time that the vector set is of the same format.

`NOQUANT`, `Q8`, and `BIN` are mutually exclusive.

EF build-exploration-factor

plays a role in the effort made to find good candidates when connecting the new node to the existing Hierarchical Navigable Small World (HNSW) graph. The default is 200. Using a larger value may help in achieving a better recall. To improve the recall it is also possible to increase EF during VSIM searches.

SETATTR attributes

associates attributes in the form of a JavaScript object to the newly created entry or updates the attributes (if they already exist).
It is the same as calling the VSETATTR command separately.

M numlinks

is the maximum number of connections that each node of the graph will have with other nodes. The default is 16. More connections means more memory, but provides for more efficient graph exploration. Nodes at layer zero (every node exists at least at layer zero) have `M * 2` connections, while the other layers only have `M` connections. For example, setting `M` to `64` will use at least 1024 bytes of memory for layer zero. That's `M * 2` connections times 8 bytes (pointers), or `128 * 8 = 1024`. For higher layers, consider the following:

- Each node appears in ~1.33 layers on average (empirical observation from HNSW papers), which works out to be 0.33 higher layers per node.
- Each of those higher layers has `M = 64` connections.

So, the additional amount of memory is approximately `0.33 × 64 × 8 ≈ 169.6` bytes per node, bringing the total memory to ~1193 bytes.

If you don't have a recall quality problem, the default is acceptable, and uses a minimal amount of memory.

Related topics

- [Vector sets]()

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

Return information

**RESP2:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): 1 if key was added; 0 if key was not added.
* [Simple error reply](../../develop/reference/protocol-spec#simple-errors): if the command was malformed.

**RESP3:**

One of the following:
* [Boolean reply](../../develop/reference/protocol-spec#booleans): true if key was added; false if key was not added.
* [Simple error reply](../../develop/reference/protocol-spec#simple-errors): if the command was malformed.

VADD mykey VALUES 3 0.1 1.2 0.5 my-element


VCARD

Summary: Return the number of elements in a vector set.

Overview

Return the number of elements in the specified vector set.

[code example]

Required arguments

key

is the name of the key that holds the vector set.

Related topics

- [Vector sets]()

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): 0 if the key doesn't exist or the number of elements contained in the vector set.

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): 0 if the key doesn't exist or the number of elements contained in the vector set.


VDIM

Summary: Return the dimension of vectors in the vector set.

Overview

Return the number of dimensions of the vectors in the specified vector set.

[code example]

If the vector set was created using the `REDUCE` option for dimensionality reduction, this command reports the reduced dimension. However, you must still use full-size vectors when performing queries with the `VSIM` command.

Required arguments

Related topics

- [Vector sets]()

Return information

**RESP2:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): the number of vector set elements.
* [Simple error reply](../../develop/reference/protocol-spec#simple-errors): if the key does not exist.

**RESP3:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): the number of vector set elements.
* [Simple error reply](../../develop/reference/protocol-spec#simple-errors): if the key does not exist.


VEMB

Summary: Return the vector associated with an element.

Overview

Return the approximate vector associated with a given element in the vector set.

[code example]

Vector sets normalize and may quantize vectors on insertion. `VEMB` reverses this process to approximate the original vector by de-normalizing and de-quantizing it.

To retrieve the raw internal representation, use the `RAW` option:

[code example]

Required arguments

key

is the name of the key that holds the vector set.

element

is the name of the element whose vector you want to retrieve.

Optional arguments

RAW

returns the raw vector data, its quantization type, and metadata such as norm and range.

Related topics

- [Vector sets]()

Return information

**RESP2:**

One of the following:
* [Array reply](../../develop/reference/protocol-spec#arrays): of real numbers as [bulk strings](../../develop/reference/protocol-spec#bulk-strings), representing the vector.
* [Array reply](../../develop/reference/protocol-spec#arrays): consisting of the following elements:
    1. The quantization type as a [simple string](../../develop/reference/protocol-spec#simple-strings): `fp32`, `bin`, or `q8`.
    1. A [bulk string](../../develop/reference/protocol-spec#bulk-strings) blob with the following raw data:
        * 4-byte floats for fp32 (little-endian encoding)
        * A bitmap for binary quantization
        * A byte array for q8
    1. The L2 norm, as a [simple string](../../develop/reference/protocol-spec#simple-strings), of the vector before normalization.
    1. (Only for q8): The quantization range as a [simple string](../../develop/reference/protocol-spec#simple-strings). Multiply this by integer components to recover normalized values.

**RESP3:**

One of the following:
* [Array reply](../../develop/reference/protocol-spec#arrays): of [doubles](../../develop/reference/protocol-spec#doubles), representing the vector.
* [Array reply](../../develop/reference/protocol-spec#arrays): consisting of the following elements:
    1. The quantization type as a [simple string](../../develop/reference/protocol-spec#simple-strings): `fp32`, `bin`, or `q8`.
    1. A [bulk string](../../develop/reference/protocol-spec#bulk-strings) blob with the following raw data:
        * 4-byte floats for fp32 (little-endian encoding)
        * A bitmap for binary quantization
        * A byte array for q8
    1. The [double](../../develop/reference/protocol-spec#doubles) L2 norm of the vector before normalization.
    1. (Only for q8): The quantization range as a [double](../../develop/reference/protocol-spec#doubles). Multiply this by integer components to recover normalized values.

VEMB word_embeddings apple RAW
1) int8
2) "\xf1\xdc\xfd\x1e\xcc%E...\xde\x1f\xfbN" # artificially shortened for this example
3) "3.1426539421081543"
4) "0.17898885905742645"


VGETATTR

Summary: Retrieve the JSON attributes of elements.

Overview

Return the JSON attributes associated with an element in a vector set.

[code example]

Required arguments

key

is the name of the key that holds the vector set.

element

is the name of the element whose attributes you want to retrieve.

Related topics

- [Vector sets]()

Return information

**RESP2:**

One of the following:
* [Simple string reply](../../develop/reference/protocol-spec#simple-strings) containing the JSON attribute(s).
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings) (null bulk string) for unknown key or element, or when no attributes exist for the given key/element pair.

**RESP3:**

One of the following:
* [Simple string reply](../../develop/reference/protocol-spec#simple-strings) containing the JSON attribute(s).
* [Null reply](../../develop/reference/protocol-spec#nulls) for unknown key or element, or when no attributes exist for the given key/element pair.


VINFO

Summary: Return information about a vector set.

Overview

Return metadata and internal details about a vector set, including size, dimensions, quantization type, and graph structure.

[code example]

Required arguments

Related topics

- [Vector sets]()

Return information

**RESP2:**

One of the following:
* [Array reply](../../develop/reference/protocol-spec#arrays) containing metadata and internal details about a vector set, including size, dimensions, quantization type, and graph structure.
* [Array reply](../../develop/reference/protocol-spec#arrays) (null array reply) for unknown key.

**RESP3:**

One of the following:
* [Array reply](../../develop/reference/protocol-spec#arrays) containing metadata and internal details about a vector set, including size, dimensions, quantization type, and graph structure.
* [Null reply](../../develop/reference/protocol-spec#nulls) for unknown key.

VINFO word_embeddings
1) quant-type
2) int8
3) vector-dim
4) (integer) 300
5) size
6) (integer) 3000000
7) max-level
8) (integer) 12
9) vset-uid
10) (integer) 1
11) hnsw-max-node-uid
12) (integer) 3000000


VISMEMBER

Summary: Check if an element exists in a vector set.

Overview

Required arguments

key

is the name of the key that holds the vector set.

element

is the name of the element you want to check for membership.

Related topics

- [Vector sets]()

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

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): `0` if the element does not exist in the vector set, or the key does not exist. `1` if the element exists in the vector set.

**RESP3:**

[Boolean reply](../../develop/reference/protocol-spec#booleans): `false` if the element does not exist in the vector set, or the key does not exist. `true` if the element exists in the vector set.


VLINKS

Summary: Return the neighbors of an element at each layer in the HNSW graph.

Overview

Return the neighbors of a specified element in a vector set. The command shows the connections for each layer of the HNSW graph.

[code example]

Use the `WITHSCORES` option to include similarity scores for each neighbor.

[code example]

Required arguments

key

is the name of the key that holds the vector set.

element

is the name of the element whose HNSW neighbors you want to inspect.

Optional arguments

WITHSCORES

includes similarity scores for each neighbor.

Related topics

- [Vector sets]()

Return information

**RESP2:**

One of the following:
* An [array](../../develop/reference/protocol-spec#arrays) of [array replies](../../develop/reference/protocol-spec#arrays) containing the names of adjacent elements as [bulk strings](../../develop/reference/protocol-spec#bulk-strings); interleaved with scores as [bulk strings](../../develop/reference/protocol-spec#bulk-strings) when used with the `WITHSCORES` option.
* [Simple error reply](../../develop/reference/protocol-spec/#simple-errors) for incorrect syntax.
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings) (null bulk string) for unknown keys and/or elements.

**RESP3:**

One of the following:
* An [array](../../develop/reference/protocol-spec#arrays) of [array replies](../../develop/reference/protocol-spec#arrays) containing the names of adjacent elements as [bulk strings](../../develop/reference/protocol-spec#bulk-strings) when used without the `WITHSCORES` option.
* An [array](../../develop/reference/protocol-spec#arrays) of [map replies](../../develop/reference/protocol-spec#maps) containing the names of adjecent elements as [bulk strings](../../develop/reference/protocol-spec#bulk-strings), together with their scores as [doubles](../../develop/reference/protocol-spec#doubles) when used with the `WITHSCORES` option.
* [Simple error reply](../../develop/reference/protocol-spec/#simple-errors) for incorrect syntax.
* [Null reply](../../develop/reference/protocol-spec#nulls) for unknown keys and/or elements.


VRANDMEMBER

Summary: Return one or multiple random members from a vector set.

Overview

Return one or more random elements from a vector set.

The behavior is similar to the `SRANDMEMBER` command:

- When called without a count, returns a single element as a bulk string.
- When called with a positive count, returns up to that many distinct elements (no duplicates).
- When called with a negative count, returns that many elements, possibly with duplicates.
- If the count exceeds the number of elements, the entire set is returned.
- If the key does not exist, the command returns `null` if no count is given, or an empty array if a count is provided.

[code example]

Return a single random element:

[code example]

Return two distinct random elements:

[code example]

Return 3 random elements with possible duplicates:

[code example]

Request more elements than exist in the set:

[code example]

When the key doesn't exist:

[code example]

[code example]

This command is useful for:

- Sampling elements for testing or training.
- Generating random queries for performance testing.

Internally:

- For small counts (less than 20% of the set size), a dictionary is used to ensure uniqueness.
- For large counts (more than 20% of the set size), a linear scan provides faster performance, though results may be less random.

Required arguments

key

is the name of the key that holds the vector set.

Optional arguments

count

specifies the number of elements to return. Positive values return distinct elements; negative values allow duplicates.

Related topics

- [Vector sets]()

Return information

**RESP2:**

One of the following:
* [Array reply](../../develop/reference/protocol-spec#arrays) containing the names of count random elements as [strings](../../develop/reference/protocol-spec#simple-strings).
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings) (null bulk string) for unknown keys.
* [Array reply](../../develop/reference/protocol-spec#arrays) (empty array) for unknown keys when a count is specified.

**RESP3:**

One of the following:
* [Array reply](../../develop/reference/protocol-spec#arrays) containing the names of *count* random elements as [strings](../../develop/reference/protocol-spec#simple-strings).
* [Null reply](../../develop/reference/protocol-spec#nulls) for unknown keys.
* [Array reply](../../develop/reference/protocol-spec#arrays) (empty array) for unknown keys when a count is specified.

VADD vset VALUES 3 1 0 0 elem1
VADD vset VALUES 3 0 1 0 elem2
VADD vset VALUES 3 0 0 1 elem3

VRANDMEMBER vset 2
1) "elem1"
2) "elem3"

VRANDMEMBER vset -3
1) "elem2"
2) "elem2"
3) "elem1"

VRANDMEMBER vset 10
1) "elem1"
2) "elem2"
3) "elem3"


VRANGE

Summary: Return elements in a lexicographical range

Overview

The `VRANGE` command provides a stateless iterator for the elements inside a vector set. It allows you to retrieve all the elements inside a vector set in small amounts for each call, without an explicit cursor, and with guarantees about what you will miss in case the vector set is changing (elements added and/or removed) during the iteration.

The command returns elements in lexicographical order, using byte-by-byte comparison (like `memcmp()`) to establish a total order among elements.

Required arguments

key

The name of the vector set key from which to retrieve elements.

start

The starting point of the lexicographical range. Can be:
- A string prefixed with `[` for inclusive range (e.g., `[Redis`)
- A string prefixed with `(` for exclusive range (e.g., `(a7`)
- The special symbol `-` to indicate the minimum element

end

The ending point of the lexicographical range. Can be:
- A string prefixed with `[` for inclusive range
- A string prefixed with `(` for exclusive range
- The special symbol `+` to indicate the maximum element

Optional arguments

count

The maximum number of elements to return. If `count` is negative, the command returns all elements in the specified range (which may block the server for a long time with large sets).

Examples

Retrieve the first 10 elements starting from the string "Redis" (inclusive):

[code example]

Iterate through all elements, 10 at a time:

[code example]

Continue iteration from the last element of the previous result (exclusive):

[code example]

Return all elements in the set (use with caution):

[code example]

Return information

**RESP2:**

One of the following:

- [Array reply]() of elements in lexicographical order within the specified range.
- [Array reply]() (empty array) if the key doesn't exist.

**RESP3:**

One of the following:

- [Array reply]() of elements in lexicographical order within the specified range.
- [Array reply]() (empty array) if the key doesn't exist.

Behavior

- **Iteration guarantees**: Each range will produce exactly the elements that were present in the range at the moment the `VRANGE` command was executed.
- **Concurrent modifications**: Elements removed or added during iteration may or may not be returned, depending on when they were modified.
- **Empty key**: If the key doesn't exist, returns an empty array.


VREM

Summary: Remove an element from a vector set.

Overview

Remove an element from a vector set.

[code example]

`VREM` reclaims memory immediately. It does not use tombstones or logical deletions, making it safe to use in long-running applications that frequently update the same vector set.

Required arguments

key

is the name of the key that holds the vector set.

element

is the name of the element to remove from the vector set.

Related topics

- [Vector sets]()

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

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): 0 if either element or key do not exist; 1 if the element was removed.

**RESP3:**

[Boolean reply](../../develop/reference/protocol-spec#booleans): false if either element or key do not exist; true if the element was removed.

VADD vset VALUES 3 1 0 1 bar
(integer) 1

VREM vset bar
(integer) 1

VREM vset bar
(integer) 0


VSETATTR

Summary: Associate or remove the JSON attributes of elements.

Overview

Associate a JSON object with an element in a vector set. Use this command to store attributes that can be used in filtered similarity searches with `VSIM`.

You can also update existing attributes or delete them by setting an empty string.

[code example]

To remove attributes, pass an empty JSON string:

[code example]

Required arguments

key

is the name of the key that holds the vector set.

element

is the name of the element whose attributes you want to set or remove.

json

is a valid JSON string. Use an empty string (`""`) to delete the attributes.

Related topics

- [Vector sets]()

Return information

**RESP2:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): 0 if either the key or element does not exist; 1 if the attributes were successfully added to the element.
* [Simple error reply](../../develop/reference/protocol-spec/#simple-errors) for improperly specified attribute string.

**RESP3:**

One of the following:
* [Boolean reply](../../develop/reference/protocol-spec#booleans): false if either the key or element does not exist; true if the attributes were successfully added to the element.
* [Simple error reply](../../develop/reference/protocol-spec/#simple-errors) for improperly specified attribute string.

VSETATTR key element "{\"type\": \"fruit\", \"color\": \"red\"}"


VSIM

Summary: Return elements by vector similarity.

Overview

Return elements similar to a given vector or element. Use this command to perform approximate or exact similarity searches within a vector set.

You can query using either a vector (via `FP32` or `VALUES num`) or by referencing another element (using `ELE`). Optional parameters let you control the search behavior, such as score output, result count, and filtering options.

[code example]

You can include similarity scores, attributes (if any), and limit the number of results:

[code example]

Set the `EF` (exploration factor) to improve recall at the cost of performance. Use the `TRUTH` option to perform an exact linear scan, useful for benchmarking. The `NOTHREAD` option runs the search in the main thread and may increase server latency.

Required arguments

key

is the name of the key that holds the vector set data.

ELE | FP32 | VALUES num

specifies how the input vector is provided. Use `ELE` to refer to an existing element, `FP32` for binary float format (little-endian encoding required), or `VALUES num` for a list of stringified float values.

vector or element

is either the vector data (for `FP32` or `VALUES`) or the name of the element (for `ELE`) to use as the similarity reference.

Optional arguments

WITHSCORES

returns the similarity score (from 1 to 0) alongside each result. A score of 1 is identical; 0 is the opposite.

WITHATTRIBS

returns, for each element, the JSON attribute associated with the element or NULL when no attributes are present.

COUNT num

limits the number of returned results to `num`.

EPSILON delta

is a floating point number between 0 and 1. It is used to retrieve elements that have a distance that is no further than the specified `delta`. In vector sets, returned elements have a similarity score (when compared to the query vector) that is between 1 and 0, where 1 means identical and 0 means opposite vectors. For example, if the `EPSILON` option is specified with an argument of `0.2`, it means only elements that have a similarity of 0.8 or better (a distance < 0.2) are returned. This is useful when you specify a large `COUNT`, but you don't want elements that are too far away from the query vector.

EF search-exploration-factor

controls the search effort. Higher values explore more nodes, improving recall at the cost of speed. Typical values range from 50 to 1000.

FILTER expression

applies a filter expression to restrict matching elements. See the filtered search section for syntax details.

FILTER-EF max-filtering-effort

limits the number of filtering attempts for the `FILTER` expression. See the filtered search section for more.

TRUTH

forces an exact linear scan of all elements, bypassing the HNSW graph. Use for benchmarking or to calculate recall. This is significantly slower (O(N)).

NOTHREAD

executes the search in the main thread instead of a background thread. Useful for small vector sets or benchmarks. This may block the server during execution.

Related topics

- [Vector sets]()

Return information

**RESP2:**

One of the following:
* [Simple error reply](../../develop/reference/protocol-spec/#simple-errors) for an unknown element.
* [Array reply](../../develop/reference/protocol-spec#arrays) (empty array) for an unknown key.
* [Array reply](../../develop/reference/protocol-spec#arrays) with matching elements.
* With the `WITHSCORES` option, an [array reply](../../develop/reference/protocol-spec#arrays) with matching [bulk string]() elements juxtaposed with [bulk string]() as floating-point scores.
* With the `WITHSCORES` and `WITHATTRIBS` options, an [array reply](../../develop/reference/protocol-spec#arrays) with matching [bulk string]() elements, and two additional elements: (1) a [bulk string]() as floating-point score and (2) a [bulk string]() representing the JSON attribute associated with the element or [nil (null bulk string)]() for the elements missing an attribute.

**RESP3:**

One of the following:
* [Simple error reply](../../develop/reference/protocol-spec/#simple-errors) for unknown element.
* [Array reply](../../develop/reference/protocol-spec#arrays) (empty array) for unknown key.
* [Array reply](../../develop/reference/protocol-spec#arrays) with matching elements.
* With the `WITHSCORES` option, a [map reply](../../develop/reference/protocol-spec#maps) with matching [bulk string]() elements (keys) and  [double](../../develop/reference/protocol-spec#doubles) scores (values).
* With the `WITHSCORES` and `WITHATTRIBS` options, a [Map reply](../../develop/reference/protocol-spec#maps) with matching [bulk string]() elements (keys), and an additional array (values) with the following elements: (1) a [double reply]()  for the score and (2) a [bulk string]() representing the JSON attribute associated with the element or [null]() for the elements missing an attribute.

VSIM word_embeddings ELE apple
1) "apple"
2) "apples"
3) "pear"
4) "fruit"
5) "berry"
6) "pears"
7) "strawberry"
8) "peach"
9) "potato"
10) "grape"


WAIT

Summary: Blocks until the asynchronous replication of all preceding write commands sent by the connection is completed.

Overview

This command blocks the current client until all the previous write commands
are successfully transferred and acknowledged by at least the number
of replicas you specify in the `numreplicas` argument. If the value
you specify for the `timeout` argument (in milliseconds) is reached, the command
returns even if the specified number of replicas were not yet reached.

The command **will always return** the number of replicas that acknowledged
the write commands sent by the current client before the `WAIT` command, both in the case where
the specified number of replicas are reached, or when the timeout is reached.

A few remarks:

1. When `WAIT` returns, all the previous write commands sent in the context of the current connection are guaranteed to be received by the number of replicas returned by `WAIT`.
2. If the command is sent as part of a [`MULTI`]() transaction (since Redis 7.0, any context that does not allow blocking, such as inside scripts), the command does not block but instead just return ASAP the number of replicas that acknowledged the previous write commands.
3. A timeout of 0 means to block forever.
4. Since `WAIT` returns the number of replicas reached both in case of failure and success, the client should check that the returned value is equal or greater to the replication level it demanded.

Consistency and WAIT
---

Note that `WAIT` does not make Redis a strongly consistent store: while synchronous replication is part of a replicated state machine, it is not the only thing needed. However in the context of Sentinel or Redis Cluster failover, `WAIT` improves the real world data safety.

Specifically if a given write is transferred to one or more replicas, it is more likely (but not guaranteed) that if the master fails, we'll be able to promote, during a failover, a replica that received the write: both Sentinel and Redis Cluster will do a best-effort attempt to promote the best replica among the set of available replicas.

However this is just a best-effort attempt so it is possible to still lose a write synchronously replicated to multiple replicas.

Implementation details
---

Since the introduction of partial resynchronization with replicas (PSYNC feature) Redis replicas asynchronously ping their master with the offset they already processed in the replication stream. This is used in multiple ways:

1. Detect timed out replicas.
2. Perform a partial resynchronization after a disconnection.
3. Implement `WAIT`.

In the specific case of the implementation of `WAIT`, Redis remembers, for each client, the replication offset of the produced replication stream when a given
write command was executed in the context of a given client. When `WAIT` is
called Redis checks if the specified number of replicas already acknowledged
this offset or a greater one.

Examples

[code example]

In the following example the first call to `WAIT` does not use a timeout and asks for the write to reach 1 replica. It returns with success. In the second attempt instead we put a timeout, and ask for the replication of the write to two replicas. Since there is a single replica available, after one second `WAIT` unblocks and returns 1, the number of replicas reached.

| Redis
Software | Redis
Cloud | Notes |
|:----------------------|:-----------------|:------|
| ✅ Standard
<nobr>❌ Active-Active\*</nobr> | ❌ Standard**
<nobr>❌ Active-Active</nobr> | \*For Active-Active databases, `WAIT` commands are supported for primary and replica shard replication. You can contact support to enable `WAIT` for local replicas only. `WAIT` is not supported for cross-instance replication.

\*\*`WAIT` commands are supported on Redis Cloud Flexible subscriptions. |

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): the command returns the number of replicas reached by all the writes performed in the context of the current connection.

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): the number of replicas reached by all the writes performed in the context of the current connection.

> SET foo bar
OK
> WAIT 1 0
(integer) 1
> WAIT 2 1000
(integer) 1


WAITAOF

Summary: Blocks until all of the preceding write commands sent by the connection are written to the append-only file of the master and/or replicas.

Overview

This command blocks the current client until all previous write commands by that client are acknowledged as having been fsynced to the AOF of the local Redis and/or at least the specified number of replicas.

`numlocal` represents the number of local fsyncs required to be confirmed before proceeding.
When `numlocal` is set to 1, the command blocks until the data written to the Redis instance is confirmed to be persisted to the local AOF file.
The value 0 disables this check.

If the timeout, specified in milliseconds, is reached, the command returns even if the specified number of acknowledgments has not been met.

The command **will always return** the number of masters and replicas that have fsynced all write commands sent by the current client before the `WAITAOF` command, both in the case where the specified thresholds were met, and when the timeout is reached.

A few remarks:

1. When `WAITAOF` returns, all the previous write commands sent in the context of the current connection are guaranteed to be fsynced to the AOF of at least the number of masters and replicas returned by `WAITAOF`.
2. If the command is sent as part of a [`MULTI`]() transaction (or any other context that does not allow blocking, such as inside scripts), the command does not block but instead returns immediately the number of masters and replicas that fsynced all previous write commands.
3. A timeout of 0 means to block forever.
4. Since `WAITAOF` returns the number of fsyncs completed both in case of success and timeout, the client should check that the returned values are equal or greater than the persistence level required.
5. `WAITAOF` cannot be used on replica instances, and the `numlocal` argument cannot be non-zero if the local Redis does not have AOF enabled.

Limitations
---
It is possible to write a module or Lua script that propagate writes to the AOF but not the replication stream.
(For modules, this is done using the `fmt` argument to `RedisModule_Call` or `RedisModule_Replicate`; For Lua scripts, this is achieved using `redis.set_repl`.)

These features are incompatible with the `WAITAOF` command as it is currently implemented, and using them in combination may result in incorrect behavior.

Consistency and WAITAOF
---

Note that, similarly to [`WAIT`](), `WAITAOF` does not make Redis a strongly-consistent store.
Unless waiting for all members of a cluster to fsync writes to disk, data can still be lost during a failover or a Redis restart.
However, `WAITAOF` does improve real-world data safety.

Implementation details
---

Since Redis 7.2, Redis tracks and increments the replication offset even when no replicas are configured (as long as AOF exists).

In addition, Redis replicas asynchronously ping their master with two replication offsets: the offset they have processed in the replication stream, and the offset they have fsynced to their AOF.

Redis remembers, for each client, the replication offset of the produced replication stream when the last write command was executed in the context of that client.
When `WAITAOF` is called, Redis checks if the local Redis and/or the specified number of replicas have confirmed fsyncing this offset or a greater one to their AOF.

Examples

[code example]

In the above example, the first call to `WAITAOF` does not use a timeout and asks for the write to be fsynced to the local Redis only; it returns with [1, 0] when this is completed.

In the second attempt we instead specify a timeout, and ask for the write to be confirmed as fsynced by a single replica.
Since there are no connected replicas, the `WAITAOF` command unblocks after one second and again returns [1, 0], indicating the write has been fsynced on the local Redis but no replicas.

| 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): The command returns an array of two integers:
1. The first is the number of local Redises (0 or 1) that have fsynced to AOF  all writes performed in the context of the current connection
2. The second is the number of replicas that have acknowledged doing the same.

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): The command returns an array of two integers:
1. The first is the number of local Redises (0 or 1) that have fsynced to AOF  all writes performed in the context of the current connection
2. The second is the number of replicas that have acknowledged doing the same.

> SET foo bar
OK
> WAITAOF 1 0 0
1) (integer) 1
2) (integer) 0
> WAITAOF 0 1 1000
1) (integer) 1
2) (integer) 0


WATCH

Summary: Monitors changes to keys to determine the execution of a transaction.

Overview

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

Marks the given keys to be watched for conditional execution of a
[transaction][tt].

[tt]: /develop/interact/transactions

Return information

**RESP2:**

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

**RESP3:**

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


XACK

Summary: Returns the number of messages that were successfully acknowledged by the consumer group member of a stream.

Overview

The `XACK` command removes one or multiple messages from the
*Pending Entries List* (PEL) of a stream consumer group. A message is pending,
and as such stored inside the PEL, when it was delivered to some consumer,
normally as a side effect of calling [`XREADGROUP`](), or when a consumer took
ownership of a message calling [`XCLAIM`](). The pending message was delivered to
some consumer but the server is yet not sure it was processed at least once.
So new calls to [`XREADGROUP`]() to grab the messages history for a consumer
(for instance using an ID of 0), will return such message.
Similarly the pending message will be listed by the [`XPENDING`]() command,
that inspects the PEL.

Once a consumer *successfully* processes a message, it should call `XACK`
so that such message does not get processed again, and as a side effect,
the PEL entry about this message is also purged, releasing memory from the
Redis server.

Examples

[code example]

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): The command returns the number of messages successfully acknowledged. Certain message IDs may no longer be part of the PEL (for example because they have already been acknowledged), and XACK will not count them as successfully acknowledged.

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): The command returns the number of messages successfully acknowledged. Certain message IDs may no longer be part of the PEL (for example because they have already been acknowledged), and XACK will not count them as successfully acknowledged.

redis> XACK mystream mygroup 1526569495631-0
(integer) 1


XACKDEL

Summary: Acknowledges and conditionally deletes one or multiple entries for a stream consumer group.

Overview

Acknowledges and conditionally deletes one or multiple entries (messages) for a stream consumer group at the specified `key`.

`XACKDEL` combines the functionality of [`XACK`]() and [`XDEL`]() in Redis Streams. It acknowledges the specified entry IDs in the given consumer group and simultaneously attempts to delete the corresponding entries from the stream.

Required arguments

key

The name of the stream key.

group

The name of the consumer group.

IDS numids id [id ...]

The IDS block specifying which entries to acknowledge and delete:
- `numids`: The number of IDs that follow
- `id [id ...]`: One or more stream entry IDs to acknowledge and delete

Optional arguments

KEEPREF | DELREF | ACKED

Specifies how to handle consumer group references when acknowledging and deleting entries. Available since Redis 8.2. If no option is specified, `KEEPREF` is used by default:

- `KEEPREF` (default): Acknowledges the entries in the specified consumer group and deletes the entries from the stream, but preserves existing references to these entries in all consumer groups' PEL (Pending Entries List).
- `DELREF`: Acknowledges the entries in the specified consumer group, deletes the entries from the stream, and also removes all references to these entries from all consumer groups' pending entry lists, effectively cleaning up all traces of the entries. If an entry ID is not in the stream, but there are dangling references, `XACKDEL` with `DELREF` would still remove all those references.
- `ACKED`: Acknowledges the entries in the specified consumer group and only deletes entries that were read and acknowledged by all consumer groups.

This command is particularly useful when you want to both acknowledge entry processing and clean up the stream in a single atomic operation, providing fine-grained control over how entry references are handled.

When using multiple consumer groups, users are encouraged to use `XACKDEL` with the `ACKED` option instead of `XACK` and `XDEL`, simplifying the application logic.

Examples

[code example]

Return information

**RESP2:**

One of the following:

* [Array reply](): -1 for each requested ID when the given key does not exist.
* [Array reply](): For each ID:
    * [Integer reply](): 1 if the entry was acknowledged and deleted from the stream.
    * [Integer reply](): -1 if no such ID exists in the provided stream key.
    * [Integer reply](): 2 if the entry was acknowledged but not deleted, as there are still dangling references (ACKED option).

**RESP3:**

One of the following:

* [Array reply](): -1 for each requested ID when the given key does not exist.
* [Array reply](): For each ID:
    * [Integer reply](): 1 if the entry was acknowledged and deleted from the stream.
    * [Integer reply](): -1 if no such ID exists in the provided stream key.
    * [Integer reply](): 2 if the entry was acknowledged but not deleted, as there are still dangling references (ACKED option).

> XADD mystream * field1 value1
"1755870377536-0"
> XADD mystream * field2 value2
"1755870387045-0"
> XGROUP CREATE mystream mygroup 0
OK
> XREADGROUP GROUP mygroup consumer1 COUNT 2 STREAMS mystream >
1) 1) "mystream"
   2) 1) 1) "1755870377536-0"
         2) 1) "field1"
            2) "value1"
      2) 1) "1755870387045-0"
         2) 1) "field2"
            2) "value2"
> XPENDING mystream mygroup
1) (integer) 2
2) "1755870377536-0"
3) "1755870387045-0"
4) 1) 1) "consumer1"
      2) "2"
> XACKDEL mystream mygroup KEEPREF IDS 2 1755870377536-0 1755870387045-0
1) (integer) 1
2) (integer) 1
> XPENDING mystream mygroup
1) (integer) 0
2) (nil)
3) (nil)
4) (nil)
> XRANGE mystream - +
(empty array)