HDEL

Summary: Deletes one or more fields and their values from a hash. Deletes the hash if no fields remain.

Examples

#### Code Examples

Foundational: Delete one or more fields from a hash using HDEL (returns count of deleted fields, ignores non-existent fields)

**Difficulty:** Beginner

**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:

HSET myhash field1 "foo"
HDEL myhash field1
HDEL myhash field2

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): the number of fields that were removed from the hash, excluding any specified but non-existing fields.

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): The number of fields that were removed from the hash, excluding any specified but non-existing fields.

HSET myhash field1 "foo"
(integer) 1
HDEL myhash field1
(integer) 1
HDEL myhash field2
(integer) 0

#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 hash with fields
    reply = redisCommand(c, "HSET %s %s %s %s %s",
        "myhash", "field1", "Hello", "field2", "World");
    freeReplyObject(reply);

    // Get multiple fields at once
    reply = redisCommand(c, "HMGET %s %s %s %s",
        "myhash", "field1", "field2", "nofield");

    printf("HMGET myhash field1 field2 nofield:\n");
    for (size_t i = 0; i < reply->elements; i++) {
        if (reply->element[i]->type == REDIS_REPLY_NIL) {
            printf("  [%zu]: null\n", i);
        } else {
            printf("  [%zu]: %s\n", i, reply->element[i]->str);
        }
    }
    // >>> [0]: Hello
    // >>> [1]: World
    // >>> [2]: null

    freeReplyObject(reply);

    redisFree(c);

    return 0;
}

bool hdelRes1 = db.HashSet("myhash", "field1", "foo");

        RedisValue hdelRes2 = db.HashDelete("myhash", "field1");
        Console.WriteLine(hdelRes2);    // >>> 1

        RedisValue hdelRes3 = db.HashDelete("myhash", "field1");
        Console.WriteLine(hdelRes3);    // >>> 0

hdel1, err := rdb.HSet(ctx, "myhash", "field1", "foo").Result()

	if err != nil {
		panic(err)
	}

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

	hdel2, err := rdb.HDel(ctx, "myhash", "field1").Result()

	if err != nil {
		panic(err)
	}

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

	hdel3, err := rdb.HDel(ctx, "myhash", "field2").Result()

	if err != nil {
		fmt.Println(err)
	}

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

Map<String, String> hDelExampleParams = new HashMap<>();
            hDelExampleParams.put("field1", "foo");

            CompletableFuture<Void> hDelExample = asyncCommands.hset("myhash", hDelExampleParams).thenCompose(res1 -> {
                System.out.println(res1); // >>> 1
                return asyncCommands.hdel("myhash", "field1");
            }).thenCompose(res2 -> {
                System.out.println(res2); // >>> 1
                return asyncCommands.hdel("myhash", "field2");
            }).thenAccept(res3 -> {
                System.out.println(res3); // >>> 0
            }).toCompletableFuture();

Map<String, String> hDelExampleParams = new HashMap<>();
            hDelExampleParams.put("field1", "foo");

            Mono<Long> hDelExample1 = reactiveCommands.hset("myhash", hDelExampleParams).doOnNext(result -> {
                System.out.println(result); // >>> 1
            });

            hDelExample1.block();

            Mono<Long> hDelExample2 = reactiveCommands.hdel("myhash", "field1").doOnNext(result -> {
                System.out.println(result); // >>> 1
            });

            hDelExample2.block();

            Mono<Long> hDelExample3 = reactiveCommands.hdel("myhash", "field2").doOnNext(result -> {
                System.out.println(result); // >>> 0
            });

Map<String, String> hDelExampleParams = new HashMap<>();
        hDelExampleParams.put("field1", "foo");

        long hDelResult1 = jedis.hset("myhash", hDelExampleParams);
        System.out.println(hDelResult1);    // >>> 1

        long hDelResult2 = jedis.hdel("myhash", "field1");
        System.out.println(hDelResult2);    // >>> 1

        long hDelResult3 = jedis.hdel("myhash", "field2");
        System.out.println(hDelResult3);    // >>> 0

const hDel1 = await client.hSet('myhash', 'field1', 'Hello')
console.log(hDel1) // 1

const hDel2 = await client.hDel('myhash', 'field1')
console.log(hDel2) // 1

const hDel3 = await client.hDel('myhash', 'field2')
console.log(hDel3) // 0

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

const redis = new Redis();

await redis.hset('myhash', { field1: 'Hello', field2: 'World' });

const hmgetResult = await redis.hmget('myhash', 'field1', 'field2', 'nofield');
console.log(hmgetResult); // >>> ['Hello', 'World', null]

redis.disconnect();

$hDelResult1 = $this->redis->hset('myhash', 'field1', 'foo');
        echo "HSET myhash field1 foo: " . $hDelResult1 . "\n"; // >>> 1

        $hDelResult2 = $this->redis->hdel('myhash', 'field1');
        echo "HDEL myhash field1: " . $hDelResult2 . "\n"; // >>> 1

        $hDelResult3 = $this->redis->hdel('myhash', 'field2');
        echo "HDEL myhash field2: " . $hDelResult3 . "\n"; // >>> 0

hdel1 = r.hset("myhash", "field1", "foo")
print(hdel1)
# >>> 1

hdel2 = r.hdel("myhash", "field1")
print(hdel2)
# >>> 1

hdel3 = r.hdel("myhash", "field2")
print(hdel3)
# >>> 0

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

        match r.hdel("myhash", "field1").await {
            Ok(hdel2) => {
                let hdel2: Option<i32> = hdel2;
                match hdel2 {
                    Some(value) => {
                        println!("{value}");    // >>> 1
                    },
                    None => {
                        println!("None");
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }

        match r.hdel("myhash", "field2").await {
            Ok(hdel3) => {
                let hdel3: Option<i32> = hdel3;
                match hdel3 {
                    Some(value) => {
                        println!("{value}");    // >>> 0
                    },
                    None => {
                        println!("None");
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }

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

        match r.hdel("myhash", "field1") {
            Ok(hdel2) => {
                let hdel2: Option<i32> = hdel2;
                match hdel2 {
                    Some(value) => {
                        println!("{value}");    // >>> 1
                    },
                    None => {
                        println!("None");
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }

        match r.hdel("myhash", "field2") {
            Ok(hdel3) => {
                let hdel3: Option<i32> = hdel3;
                match hdel3 {
                    Some(value) => {
                        println!("{value}");    // >>> 0
                    },
                    None => {
                        println!("None");
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }


HELLO

Summary: Handshakes with the Redis server.

Overview

Switch to a different protocol, optionally authenticating and setting the
connection's name, or provide a contextual client report.

Redis version 6 and above supports two protocols: the old protocol, RESP2, and
a new one introduced with Redis 6, RESP3. RESP3 has certain advantages since
when the connection is in this mode, Redis is able to reply with more semantical
replies: for instance, [`HGETALL`]() will return a *map type*, so a client library
implementation no longer requires to know in advance to translate the array into
a hash before returning it to the caller. For a full coverage of RESP3, please
check the [RESP3 specification](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md).

In Redis 6 connections start in RESP2 mode, so clients implementing RESP2 do
not need to updated or changed. There are no short term plans to drop support for
RESP2, although future version may default to RESP3.

`HELLO` always replies with a list of current server and connection properties,
such as: versions, modules loaded, client ID, replication role and so forth.
When called without any arguments in Redis 6.2 and its default use of RESP2
protocol, the reply looks like this:

    > HELLO
     1) "server"
     2) "redis"
     3) "version"
     4) "255.255.255"
     5) "proto"
     6) (integer) 2
     7) "id"
     8) (integer) 5
     9) "mode"
    10) "standalone"
    11) "role"
    12) "master"
    13) "modules"
    14) (empty array)

Clients that want to handshake using the RESP3 mode need to call the `HELLO`
command and specify the value "3" as the `protover` argument, like so:

    > HELLO 3
    1# "server" => "redis"
    2# "version" => "6.0.0"
    3# "proto" => (integer) 3
    4# "id" => (integer) 10
    5# "mode" => "standalone"
    6# "role" => "master"
    7# "modules" => (empty array)

Because `HELLO` replies with useful information, and given that `protover` is
optional or can be set to "2", client library authors may consider using this
command instead of the canonical [`PING`]() when setting up the connection.

When called with the optional `protover` argument, this command switches the
protocol to the specified version and also accepts the following options:

* `AUTH <username> <password>`: directly authenticate the connection in addition to switching to the specified protocol version. This makes calling [`AUTH`]() before `HELLO` unnecessary when setting up a new connection. Note that the `username` can be set to "default" to authenticate against a server that does not use ACLs, but rather the simpler `requirepass` mechanism of Redis prior to version 6.
* `SETNAME <clientname>`: this is the equivalent of calling [`CLIENT SETNAME`]().

Redis Software and Redis Cloud compatibility

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

Return information

**RESP2:**

[Map reply](../../develop/reference/protocol-spec#maps): a list of server properties.
[Simple error reply](../../develop/reference/protocol-spec#simple-errors): if the `protover` requested does not exist.

**RESP3:**

[Map reply](../../develop/reference/protocol-spec#maps): a list of server properties.
[Simple error reply](../../develop/reference/protocol-spec#simple-errors): if the `protover` requested does not exist.


HEXISTS

Summary: Determines whether a field exists in a hash.

Overview

Returns if `field` is an existing field in the hash stored at `key`.

Examples

HSET myhash field1 "foo"
HEXISTS myhash field1
HEXISTS myhash field2

Return information

**RESP2:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): `0` if the hash does not contain the field, or the key does not exist.
* [Integer reply](../../develop/reference/protocol-spec#integers): `1` if the hash contains the field.

**RESP3:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): `0` if the hash does not contain the field, or the key does not exist.
* [Integer reply](../../develop/reference/protocol-spec#integers): `1` if the hash contains the field.


HEXPIRE

Summary: Set expiration for hash fields using relative time to expire (seconds)

Options

The `HEXPIRE` command supports a set of options:

* `NX` -- For each specified field, set expiration only when the field has no expiration.
* `XX` -- For each specified field, set expiration only when the field has an existing expiration.
* `GT` -- For each specified field, set expiration only when the new expiration is greater than current one.
* `LT` -- For each specified field, set expiration only when the new expiration is less than current one.

A non-volatile field is treated as an infinite TTL for the purpose of `GT` and `LT`.
The `NX`, `XX`, `GT`, and `LT` options are mutually exclusive.

Refreshing expires

You can call `HEXPIRE` using as argument a field that already has an
existing TTL set.
In this case, the time to live is _updated_ to the new value.

Redis Search and field expiration

Starting with Redis 8, Redis Search has enhanced behavior when handling expiring hash fields. For detailed information about how [`FT.SEARCH`]() and [`FT.AGGREGATE`]() commands interact with expiring hash fields, see [Key and field expiration behavior]().

Examples

#### Code Examples

Field expiration: Set TTL on individual hash fields using HEXPIRE with conditional options (NX, XX, GT, LT) when you need fine-grained control over field lifecycle

**Difficulty:** Intermediate

**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:

HEXPIRE no-key 20 NX FIELDS 2 field1 field2
HSET mykey field1 "hello" field2 "world"
HEXPIRE mykey 10 FIELDS 3 field1 field2 field3
HGETALL mykey

Return information

**RESP2:**

One of the following:
* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `0` if the specified NX | XX | GT | LT condition has not been met.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `1` if the expiration time was set/updated.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `2` when `HEXPIRE`/`HPEXPIRE` is called with 0 seconds/milliseconds or when `HEXPIREAT`/`HPEXPIREAT` is called with a past Unix time in seconds/milliseconds.
* [Simple error reply](../../develop/reference/protocol-spec#simple-errors):
    - if parsing failed, mandatory arguments are missing, unknown arguments are specified, or argument values are of the wrong type or out of range.
    - if the provided key exists but is not a hash.

**RESP3:**

One of the following:
* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `0` if the specified NX | XX | GT | LT condition has not been met.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `1` if the expiration time was set/updated.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `2` when `HEXPIRE`/`HPEXPIRE` is called with 0 seconds/milliseconds or when `HEXPIREAT`/`HPEXPIREAT` is called with a past Unix time in seconds/milliseconds.
* [Simple error reply](../../develop/reference/protocol-spec#simple-errors):
    - if parsing failed, mandatory arguments are missing, unknown arguments are specified, or argument values are of the wrong type or out of range.
    - if the provided key exists but is not a hash.

HEXPIRE no-key 20 NX FIELDS 2 field1 field2
(nil)
HSET mykey field1 "hello" field2 "world"
(integer) 2
HEXPIRE mykey 10 FIELDS 3 field1 field2 field3
1) (integer) 1
2) (integer) 1
3) (integer) -2
HGETALL mykey

// Set up hash with fields
        db.HashSet("myhash",
            [
                new("field1", "Hello"),
                new("field2", "World")
            ]
        );

        ExpireResult[] hexpireRes1 = db.HashFieldExpire(
            "myhash",
            new RedisValue[] { "field1", "field2" },
            TimeSpan.FromSeconds(10)
        );
        Console.WriteLine(string.Join(", ", hexpireRes1));
        // >>> Success, Success

        long[] hexpireRes2 = db.HashFieldGetTimeToLive(
            "myhash",
            new RedisValue[] { "field1", "field2" }
        );
        Console.WriteLine(string.Join(", ", hexpireRes2));
        // >>> 10, 10 (approximately)

        // Try to set expiration on non-existent field
        ExpireResult[] hexpireRes3 = db.HashFieldExpire(
            "myhash",
            new RedisValue[] { "nonexistent" },
            TimeSpan.FromSeconds(10)
        );
        Console.WriteLine(string.Join(", ", hexpireRes3));
        // >>> NoSuchField

// Set up hash with fields
	rdb.HSet(ctx, "myhash", "field1", "Hello", "field2", "World")

	// Set expiration on hash fields
	res1, err := rdb.HExpire(ctx, "myhash", 10*time.Second, "field1", "field2").Result()

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(res1) // >>> [1 1]

	// Check TTL of the fields
	res2, err := rdb.HTTL(ctx, "myhash", "field1", "field2").Result()

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(len(res2)) // >>> 2

	// Try to set expiration on non-existent field
	res3, err := rdb.HExpire(ctx, "myhash", 10*time.Second, "nonexistent").Result()

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(res3) // >>> [-2]

	// Clean up
	rdb.Del(ctx, "myhash")

// Set up hash with fields
            Map<String, String> hExpireExampleParams = new HashMap<>();
            hExpireExampleParams.put("field1", "Hello");
            hExpireExampleParams.put("field2", "World");

            CompletableFuture<Void> hExpireExample = asyncCommands.hset("myhash", hExpireExampleParams).thenCompose(res1 -> {
                // Set expiration on hash fields
                return asyncCommands.hexpire("myhash", 10, "field1", "field2");
            }).thenCompose(res2 -> {
                System.out.println(res2);
                // >>> [1, 1]
                // Check TTL of the fields
                return asyncCommands.httl("myhash", "field1", "field2");
            }).thenCompose(res3 -> {
                System.out.println(res3.size());
                // >>> 2
                // Try to set expiration on non-existent field
                return asyncCommands.hexpire("myhash", 10, "nonexistent");
            })
                    .thenAccept(System.out::println)
                    // >>> -2
                    .toCompletableFuture();

// Set up hash with fields
            Map<String, String> hExpireExampleParams = new HashMap<>();
            hExpireExampleParams.put("field1", "Hello");
            hExpireExampleParams.put("field2", "World");

            Mono<Long> hExpireExample1 = reactiveCommands.hset("myhash", hExpireExampleParams).doOnNext(result -> {
            });

            hExpireExample1.block();

            // Set expiration on hash fields
            Mono<List<Long>> hExpireExample2 = reactiveCommands.hexpire("myhash", 10, "field1", "field2").collectList().doOnNext(result -> {
                System.out.println(result);
                // >>> [1, 1]
            });

            hExpireExample2.block();

            // Check TTL of the fields
            Mono<List<Long>> hExpireExample3 = reactiveCommands.httl("myhash", "field1", "field2").collectList().doOnNext(result -> {
                System.out.println(result.size());
                // >>> 2
            });

            hExpireExample3.block();

            // Try to set expiration on non-existent field
            Mono<List<Long>> hExpireExample4 = reactiveCommands.hexpire("myhash", 10, "nonexistent").collectList().doOnNext(result -> {
                System.out.println(result);
                // >>> [-2]
            });

// Set up hash with fields
        Map<String, String> hExpireExampleParams = new HashMap<>();
        hExpireExampleParams.put("field1", "Hello");
        hExpireExampleParams.put("field2", "World");
        jedis.hset("myhash", hExpireExampleParams);

        // Set expiration on hash fields
        List<Long> hExpireResult1 = jedis.hexpire("myhash", 10, "field1", "field2");
        System.out.println(hExpireResult1); // >>> [1, 1]

        // Check TTL of the fields
        List<Long> hExpireResult2 = jedis.httl("myhash", "field1", "field2");
        System.out.println(hExpireResult2.size()); // >>> 2

        // Try to set expiration on non-existent field
        List<Long> hExpireResult3 = jedis.hexpire("myhash", 10, "nonexistent");
        System.out.println(hExpireResult3); // >>> [-2]

// Set up hash with fields
await client.hSet('myhash', {
  'field1': 'Hello',
  'field2': 'World'
})

// Set expiration on hash fields
const res14 = await client.hExpire('myhash', ['field1', 'field2'], 10)
console.log(res14) // [1, 1]

// Check TTL of the fields
const res15 = await client.hTTL('myhash', ['field1', 'field2'])
console.log(res15) // [10, 10] (or close to 10)

// Try to set expiration on non-existent field
const res16 = await client.hExpire('myhash', ['nonexistent'], 10)
console.log(res16) // [-2]

// Set up hash with fields
        $hExpireResult1 = $this->redis->hmset('myhash', ['field1' => 'Hello', 'field2' => 'World']);
        echo "HMSET myhash field1 Hello field2 World: " . ($hExpireResult1 ? 'OK' : 'FAIL') . "\n"; // >>> OK

        // Set expiration on hash fields
        $hExpireResult2 = $this->redis->hexpire('myhash', 10, ['field1', 'field2']);
        echo "HEXPIRE myhash 10 FIELDS field1 field2: " . json_encode($hExpireResult2) . "\n"; // >>> [1,1]

        // Check TTL of the fields
        $hExpireResult3 = $this->redis->httl('myhash', ['field1', 'field2']);
        echo "HTTL myhash FIELDS field1 field2 count: " . count($hExpireResult3) . "\n"; // >>> 2

        // Try to set expiration on non-existent field
        $hExpireResult4 = $this->redis->hexpire('myhash', 10, ['nonexistent']);
        echo "HEXPIRE myhash 10 FIELDS nonexistent: " . json_encode($hExpireResult4) . "\n"; // >>> [-2]

# Set up hash with fields
r.hset("myhash", mapping={"field1": "Hello", "field2": "World"})

# Set expiration on hash fields
res12 = r.hexpire("myhash", 10, "field1", "field2")
print(res12)  # >>> [1, 1]

# Check TTL of the fields
res13 = r.httl("myhash", "field1", "field2")
print(res13)  # >>> [10, 10] (or close to 10)

# Try to set expiration on non-existent field
res14 = r.hexpire("myhash", 10, "nonexistent")
print(res14)  # >>> [-2]

// Set up hash with fields
        let hash_fields = vec![("field1", "Hello"), ("field2", "World")];
        if let Ok(res) = r.hset_multiple("myhash", &hash_fields).await {
            let res: String = res;
            println!("{res}");    // >>> OK
        }

        // Set expiration on hash fields
        match r.hexpire("myhash", 10, redis::ExpireOption::NONE, &["field1", "field2"]).await {
            Ok(res1) => {
                let res1: Vec<i32> = res1;
                println!("{:?}", res1);    // >>> [1, 1]
            },
            Err(e) => {
                println!("Error setting expiration: {e}");
                return;
            }
        }

        // Check TTL of the fields
        match r.httl("myhash", &["field1", "field2"]).await {
            Ok(res2) => {
                let res2: Vec<i32> = res2;
                println!("{}", res2.len());    // >>> 2
            },
            Err(e) => {
                println!("Error getting TTL: {e}");
                return;
            }
        }

        // Try to set expiration on non-existent field
        match r.hexpire("myhash", 10, redis::ExpireOption::NONE, &["nonexistent"]).await {
            Ok(res3) => {
                let res3: Vec<i32> = res3;
                println!("{:?}", res3);    // >>> [-2]
            },
            Err(e) => {
                println!("Error setting expiration on non-existent field: {e}");
                return;
            }
        }

// Set up hash with fields
        let hash_fields = vec![("field1", "Hello"), ("field2", "World")];
        if let Ok(res) = r.hset_multiple("myhash", &hash_fields) {
            let res: String = res;
            println!("{res}");    // >>> OK
        }

        // Set expiration on hash fields
        match r.hexpire("myhash", 10, redis::ExpireOption::NONE, &["field1", "field2"]) {
            Ok(res1) => {
                let res1: Vec<i32> = res1;
                println!("{:?}", res1);    // >>> [1, 1]
            },
            Err(e) => {
                println!("Error setting expiration: {e}");
                return;
            }
        }

        // Check TTL of the fields
        match r.httl("myhash", &["field1", "field2"]) {
            Ok(res2) => {
                let res2: Vec<i32> = res2;
                println!("{}", res2.len());    // >>> 2
            },
            Err(e) => {
                println!("Error getting TTL: {e}");
                return;
            }
        }

        // Try to set expiration on non-existent field
        match r.hexpire("myhash", 10, redis::ExpireOption::NONE, &["nonexistent"]) {
            Ok(res3) => {
                let res3: Vec<i32> = res3;
                println!("{:?}", res3);    // >>> [-2]
            },
            Err(e) => {
                println!("Error setting expiration on non-existent field: {e}");
                return;
            }
        }


HEXPIREAT

Summary: Set expiration for hash fields using an absolute Unix timestamp (seconds)

Overview

`HEXPIREAT` has the same effect and semantics as [`HEXPIRE`](), but instead of
specifying the number of seconds for the TTL (time to live), it takes
an absolute [Unix timestamp](http://en.wikipedia.org/wiki/Unix_time) in seconds since Unix epoch. A
timestamp in the past will delete the field immediately.

For the specific semantics of the command, see [`HEXPIRE`]().

Options

The `HEXPIREAT` command supports a set of options:

* `NX` -- For each specified field, set expiration only when the field has no expiration.
* `XX` -- For each specified field, set expiration only when the field has an existing expiration.
* `GT` -- For each specified field, set expiration only when the new expiration is greater than current one.
* `LT` -- For each specified field, set expiration only when the new expiration is less than current one.

A non-volatile key is treated as an infinite TTL for the purposes of `GT` and `LT`.
The `NS`, `XX`, `GT`, and `LT` options are mutually exclusive.

Example

[code example]

Return information

**RESP2:**

One of the following:
* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `0` if the specified NX, XX, GT, or LT condition has not been met.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `1` if the expiration time was set/updated.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `2` when `HEXPIRE` or `HPEXPIRE` is called with 0 seconds or milliseconds, or when `HEXPIREAT` or `HPEXPIREAT` is called with a past Unix time in seconds or milliseconds.
* [Simple error reply](../../develop/reference/protocol-spec#simple-errors):
    - if parsing failed, mandatory arguments are missing, unknown arguments are specified, or argument values are of the wrong type or out of range.
    - if the provided key exists but is not a hash.

**RESP3:**

One of the following:
* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `0` if the specified NX, XX, GT, or LT condition has not been met.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `1` if the expiration time was set/updated.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `2` when `HEXPIRE` or `HPEXPIRE` is called with 0 seconds or milliseconds, or when `HEXPIREAT` or `HPEXPIREAT` is called with a past Unix time in seconds or milliseconds.
* [Simple error reply](../../develop/reference/protocol-spec#simple-errors):
    - if parsing failed, mandatory arguments are missing, unknown arguments are specified, or argument values are of the wrong type or out of range.
    - if the provided key exists but is not a hash.

redis> HSET mykey field1 "hello" field2 "world"
(integer) 2
redis> HEXPIREAT mykey 1715704971 FIELDS 2 field1 field2
1) (integer) 1
2) (integer) 1
redis> HTTL mykey FIELDS 2 field1 field2
1) (integer) 567
2) (integer) 567


HEXPIRETIME

Summary: Returns the expiration time of a hash field as a Unix timestamp, in seconds.

Overview

Returns the absolute Unix timestamp in seconds since Unix epoch at which the given key's field(s) will expire.

See also the [`HPEXPIRETIME`]() command, which returns the same information with millisecond resolution.

Examples

[code example]

Return information

**RESP2:**

* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-1` if the field exists but has no associated expiration set.
    - [Integer reply](../../develop/reference/protocol-spec#integers): the expiration (Unix timestamp) in seconds.

**RESP3:**

* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-1` if the field exists but has no associated expiration set.
    - [Integer reply](../../develop/reference/protocol-spec#integers): the expiration (Unix timestamp) in seconds.

redis> HSET mykey field1 "hello" field2 "world"
(integer) 2
redis> HEXPIRE mykey 300  FIELDS 2 field1 field2
1) (integer) 1
2) (integer) 1
redis> HEXPIRETIME mykey FIELDS 2 field1 field2
1) (integer) 1715705914
2) (integer) 1715705914


HGET

Summary: Returns the value of a field in a hash.

Examples

#### Code Examples

Foundational: Retrieve a single field value from a hash using HGET (returns nil if field or key doesn't exist)

**Difficulty:** Beginner

**Commands:** HSET, HGET

**Complexity:**
- HSET: O(1)
- HGET: 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:

HSET myhash field1 "foo"
HGET myhash field1
HGET myhash field2

Return information

**RESP2:**

One of the following:
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): The value associated with the field.
* [Nil reply](../../develop/reference/protocol-spec#bulk-strings): If the field is not present in the hash or key does not exist.

**RESP3:**

One of the following:
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): The value associated with the field.
* [Null reply](../../develop/reference/protocol-spec#nulls): If the field is not present in the hash or key does not exist.

> HSET myhash field1 "foo"
(integer) 1
> HGET myhash field1
"foo"
> HGET myhash field2
(nil)

#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 hash with fields
    reply = redisCommand(c, "HSET %s %s %s %s %s",
        "myhash", "field1", "Hello", "field2", "World");
    freeReplyObject(reply);

    // Get multiple fields at once
    reply = redisCommand(c, "HMGET %s %s %s %s",
        "myhash", "field1", "field2", "nofield");

    printf("HMGET myhash field1 field2 nofield:\n");
    for (size_t i = 0; i < reply->elements; i++) {
        if (reply->element[i]->type == REDIS_REPLY_NIL) {
            printf("  [%zu]: null\n", i);
        } else {
            printf("  [%zu]: %s\n", i, reply->element[i]->str);
        }
    }
    // >>> [0]: Hello
    // >>> [1]: World
    // >>> [2]: null

    freeReplyObject(reply);

    redisFree(c);

    return 0;
}

bool hgetRes1 = db.HashSet("myhash", "field1", "foo");

        RedisValue hgetRes2 = db.HashGet("myhash", "field1");
        Console.WriteLine(hgetRes2);    // >>> foo

        RedisValue hgetRes3 = db.HashGet("myhash", "field2");
        Console.WriteLine(hgetRes3);    // >>> Null

res7, err := rdb.HSet(ctx, "myhash", "field1", "foo").Result()

	if err != nil {
		panic(err)
	}

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

	res8, err := rdb.HGet(ctx, "myhash", "field1").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res8) // >>> foo

	res9, err := rdb.HGet(ctx, "myhash", "field2").Result()

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(res9) // >>> <empty string>

Map<String, String> hGetExampleParams = new HashMap<>();
            hGetExampleParams.put("field1", "foo");

            CompletableFuture<Void> hGetExample = asyncCommands.hset("myhash", hGetExampleParams).thenCompose(res1 -> {
                System.out.println(res1); // >>> 1
                return asyncCommands.hget("myhash", "field1");
            }).thenCompose(res2 -> {
                System.out.println(res2); // >>> foo
                return asyncCommands.hget("myhash", "field2");
            }).thenAccept(res3 -> {
                System.out.println(res3); // >>> null
            }).toCompletableFuture();

Map<String, String> hGetExampleParams = new HashMap<>();
            hGetExampleParams.put("field1", "foo");

            Mono<Long> hGetExample1 = reactiveCommands.hset("myhash", hGetExampleParams).doOnNext(result -> {
                System.out.println(result); // >>> 1
            });

            hGetExample1.block();

            Mono<String> hGetExample2 = reactiveCommands.hget("myhash", "field1").doOnNext(result -> {
                System.out.println(result); // >>> foo
            });

            hGetExample2.block();

            Mono<String> hGetExample3 = reactiveCommands.hget("myhash", "field2").doOnNext(result -> {
                System.out.println(result); // >>> null
            });

Map<String, String> hGetExampleParams = new HashMap<>();
        hGetExampleParams.put("field1", "foo");

        long hGetResult1 = jedis.hset("myhash", hGetExampleParams);
        System.out.println(hGetResult1);    // >>> 1

        String hGetResult2 = jedis.hget("myhash", "field1");
        System.out.println(hGetResult2);    // >>> foo

        String hGetResult3 = jedis.hget("myhash", "field2");
        System.out.println(hGetResult3);    // >>> null

const res7 = await client.hSet('myhash', 'field1', 'foo')
console.log(res7) // 1

const res8 = await client.hGet('myhash', 'field1')
console.log(res8) // foo

const res9 = await client.hGet('myhash', 'field2')
console.log(res9) // null

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

const redis = new Redis();

await redis.hset('myhash', { field1: 'Hello', field2: 'World' });

const hmgetResult = await redis.hmget('myhash', 'field1', 'field2', 'nofield');
console.log(hmgetResult); // >>> ['Hello', 'World', null]

redis.disconnect();

$hGetResult1 = $this->redis->hset('myhash', 'field1', 'foo');
        echo "HSET myhash field1 foo: " . $hGetResult1 . "\n"; // >>> 1

        $hGetResult2 = $this->redis->hget('myhash', 'field1');
        echo "HGET myhash field1: " . ($hGetResult2 ?? 'null') . "\n"; // >>> foo

        $hGetResult3 = $this->redis->hget('myhash', 'field2');
        echo "HGET myhash field2: " . ($hGetResult3 ?? 'null') . "\n"; // >>> null

res7 = r.hset("myhash", "field1", "foo")
print(res7)
# >>> 1

res8 = r.hget("myhash", "field1")
print(res8)
# >>> foo

res9 = r.hget("myhash", "field2")
print(res9)
# >>> None

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

        match r.hget("myhash", "field1").await {
            Ok(res8) => {
                let res8: Option<String> = res8;
                match res8 {
                    Some(value) => {
                        println!("{value}");    // >>> foo
                    },
                    None => {
                        println!("None");
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }

        match r.hget("myhash", "field2").await {
            Ok(res9) => {
                let res9: Option<String> = res9;
                match res9 {
                    Some(_) => {
                        println!("Some value");
                    },
                    None => {
                        println!("None");    // >>> None
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }

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

        match r.hget("myhash", "field1") {
            Ok(res8) => {
                let res8: Option<String> = res8;
                match res8 {
                    Some(value) => {
                        println!("{value}");    // >>> foo
                    },
                    None => {
                        println!("None");
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }

        match r.hget("myhash", "field2") {
            Ok(res9) => {
                let res9: Option<String> = res9;
                match res9 {
                    Some(_) => {
                        println!("Some value");
                    },
                    None => {
                        println!("None");    // >>> None
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }


HGETALL

Summary: Returns all fields and values in a hash.

Examples

#### Code Examples

Foundational: Retrieve all fields and values from a hash using HGETALL (returns alternating field-value pairs, useful for loading entire hash data)

**Difficulty:** Beginner

**Commands:** HSET, HGETALL

**Complexity:**
- HSET: O(1)
- HGETALL: O(N)

**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:

HSET myhash field1 "Hello"
HSET myhash field2 "World"
HGETALL myhash

| 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): a list of fields and their values, or an empty list when key does not exist.

**RESP3:**

[Map reply](../../develop/reference/protocol-spec#maps): a map of fields and their values, or an empty list when key does not exist.

redis> HSET myhash field1 "Hello"
(integer) 1
redis> HSET myhash field2 "World"
(integer) 1
redis> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "World"

db.HashSet("myhash",
            [
                new("field1", "Hello"),
                new("field2", "World")
            ]
        );

        HashEntry[] hGetAllResult = db.HashGetAll("myhash");
        Array.Sort(hGetAllResult, (a1, a2) => a1.Name.CompareTo(a2.Name));
        Console.WriteLine(
            string.Join(", ", hGetAllResult.Select(e => $"{e.Name}: {e.Value}"))
        );
        // >>> field1: Hello, field2: World

hGetAllResult1, err := rdb.HSet(ctx, "myhash",
		"field1", "Hello",
		"field2", "World",
	).Result()

	if err != nil {
		panic(err)
	}

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

	hGetAllResult2, err := rdb.HGetAll(ctx, "myhash").Result()

	if err != nil {
		panic(err)
	}

	keys := make([]string, 0, len(hGetAllResult2))

	for key, _ := range hGetAllResult2 {
		keys = append(keys, key)
	}

	sort.Strings(keys)

	for _, key := range keys {
		fmt.Printf("Key: %v, value: %v\n", key, hGetAllResult2[key])
	}
	// >>> Key: field1, value: Hello
	// >>> Key: field2, value: World

Map<String, String> hGetAllExampleParams = new HashMap<>();
            hGetAllExampleParams.put("field1", "Hello");
            hGetAllExampleParams.put("field2", "World");

            CompletableFuture<Void> hGetAllExample = asyncCommands.hset("myhash", hGetAllExampleParams).thenCompose(res1 -> {
                return asyncCommands.hgetall("myhash");
            }).thenAccept(res2 -> {
                System.out.println(res2);
                // >>> {field1=Hello, field2=World}
            }).toCompletableFuture();

Map<String, String> hGetAllExampleParams = new HashMap<>();
            hGetAllExampleParams.put("field1", "Hello");
            hGetAllExampleParams.put("field2", "World");

            Mono<Long> hGetAllExample1 = reactiveCommands.hset("myhash", hGetAllExampleParams).doOnNext(result -> {
            });

            hGetAllExample1.block();

            Mono<Map<String, String>> hGetAllExample2 = reactiveCommands.hgetall("myhash").collectMap(
                    KeyValue::getKey, KeyValue::getValue
            ).doOnNext(result -> {
                System.out.println(result);
                // >>> {field1=Hello, field2=World}
            });

Map<String, String> hGetAllExampleParams = new HashMap<>();
        hGetAllExampleParams.put("field1", "Hello");
        hGetAllExampleParams.put("field2", "World");

        long hGetAllResult1 = jedis.hset("myhash", hGetAllExampleParams);
        System.out.println(hGetAllResult1); // >>> 2

        Map<String, String> hGetAllResult2 = jedis.hgetAll("myhash");
        System.out.println(
            hGetAllResult2.entrySet().stream()
                    .sorted((s1, s2)-> s1.getKey().compareTo(s2.getKey()))
                    .collect(toList())
                    .toString()
        );
        // >>> [field1=Hello, field2=World]

const res10 = await client.hSet(
  'myhash',
  {
    'field1': 'Hello',
    'field2': 'World'
  }
)

const res11 = await client.hGetAll('myhash')
console.log(res11) // [Object: null prototype] { field1: 'Hello', field2: 'World' }

$hGetAllResult1 = $this->redis->hmset('myhash', ['field1' => 'Hello', 'field2' => 'World']);
        echo "HMSET myhash field1 Hello field2 World: " . ($hGetAllResult1 ? 'OK' : 'FAIL') . "\n"; // >>> OK

        $hGetAllResult2 = $this->redis->hgetall('myhash');
        echo "HGETALL myhash: " . json_encode($hGetAllResult2) . "\n"; // >>> {"field1":"Hello","field2":"World"}

res10 = r.hset("myhash", mapping={"field1": "Hello", "field2": "World"})

res11 = r.hgetall("myhash")
print(res11) # >>> { "field1": "Hello", "field2": "World" }

let hash_fields = [
            ("field1", "Hello"),
            ("field2", "World"),
        ];

        if let Ok(_) = r.hset_multiple::<&str, &str, &str, String>("myhash", &hash_fields).await {
            // Fields set successfully
        }

        match r.hgetall("myhash").await {
            Ok(res11) => {
                let res11: HashMap<String, String> = res11;
                println!("{res11:?}");    // >>> {"field1": "Hello", "field2": "World"}
            },
            Err(e) => {
                println!("Error getting all hash fields: {e}");
                return;
            }
        }

let hash_fields = [
            ("field1", "Hello"),
            ("field2", "World"),
        ];

        if let Ok(_) = r.hset_multiple::<&str, &str, &str, String>("myhash", &hash_fields) {
            // Fields set successfully
        }

        match r.hgetall("myhash") {
            Ok(res11) => {
                let res11: HashMap<String, String> = res11;
                println!("{res11:?}");    // >>> {"field1": "Hello", "field2": "World"}
            },
            Err(e) => {
                println!("Error getting all hash fields: {e}");
                return;
            }
        }


HGETDEL

Summary: Returns the value of a field and deletes it from the hash.

Overview

Get and delete the value of one or more fields of a given hash key. When the last field is deleted, the key will also be deleted.

Example

[code example]

Return information

**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): a list of deleted fields and their values or `nil` for fields that do not exist.

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): a list of deleted fields and their values or `nil` for fields that do not exist.

redis> HSET mykey field1 "Hello" field2 "World" field3 "!"
(integer) 3
redis> HGETALL mykey
1) "field1"
2) "Hello"
3) "field2"
4) "World"
5) "field3"
6) "!"
redis> HGETDEL mykey FIELDS 2 field3 field4
1) "!"
2) (nil)
redis> HGETALL mykey
1) "field1"
2) "Hello"
3) "field2"
4) "World"
redis> HGETDEL mykey FIELDS 2 field1 field2
1) "Hello"
2) "World"
redis> KEYS *
(empty array)


HGETEX

Summary: Get the value of one or more fields of a given hash key, and optionally set their expiration.

Overview

Get the value of one or more fields of a given hash key and optionally set their expiration time or time-to-live (TTL).

Options

The `HGETEX` command supports a set of options:

* `EX seconds` -- Set the specified expiration time, in seconds.
* `PX milliseconds` -- Set the specified expiration time, in milliseconds.
* `EXAT unix-time-seconds` -- Set the specified Unix time at which the fields will expire, in seconds.
* `PXAT unix-time-milliseconds` -- Set the specified Unix time at which the fields will expire, in milliseconds.
* `PERSIST` -- Remove the TTL associated with the fields.

The `EX`, `PX`, `EXAT`, `PXAT`, and `PERSIST` options are mutually exclusive.

Example

[code example]

Return information

**RESP2:**

* [Array reply](../../develop/reference/protocol-spec#arrays): a list of values associated with the given fields, in the same order as they are requested.

**RESP3:**

* [Array reply](../../develop/reference/protocol-spec#arrays): a list of values associated with the given fields, in the same order as they are requested.

redis> HSET mykey field1 "Hello" field2 "World"
(integer) 2
redis> HGETEX mykey EX 120 FIELDS 1 field1
1) "Hello"
redis> HGETEX mykey EX 100 FIELDS 1 field2
1) "World"
redis> HTTL mykey FIELDS 2 field1 field2
1) (integer) 91
2) (integer) 85
redis> HTTL mykey FIELDS 3 field1 field2 field3
1) (integer) 75
2) (integer) 68
3) (integer) -2
...
redis> HTTL mykey FIELDS 3 field1 field2
1) (integer) -2
2) (integer) -2
redis> HGETALL mykey
(empty array)


HINCRBY

Summary: Increments the integer value of a field in a hash by a number. Uses 0 as initial value if the field doesn't exist.

Overview

Increments the number stored at `field` in the hash stored at `key` by
`increment`.
If `key` does not exist, a new key holding a hash is created.
If `field` does not exist the value is set to `0` before the operation is
performed.

The range of values supported by `HINCRBY` is limited to 64 bit signed integers.

Examples

Since the `increment` argument is signed, both increment and decrement
operations can be performed:

HSET myhash field 5
HINCRBY myhash field 1
HINCRBY myhash field -1
HINCRBY myhash field -10

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): the value of the field after the increment operation.

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): the value of the field after the increment operation.


HINCRBYFLOAT

Summary: Increments the floating point value of a field by a number. Uses 0 as initial value if the field doesn't exist.

Overview

Increment the specified `field` of a hash stored at `key`, and representing a
floating point number, by the specified `increment`. If the increment value
is negative, the result is to have the hash field value **decremented** instead of incremented.
If the field does not exist, it is set to `0` before performing the operation.
An error is returned if one of the following conditions occur:

* The key contains a value of the wrong type (not a hash).
* The current field content or the specified increment are not parsable as a
  double precision floating point number.

The exact behavior of this command is identical to the one of the [`INCRBYFLOAT`]()
command, please refer to the documentation of [`INCRBYFLOAT`]() for further
information.

Examples

HSET mykey field 10.50
HINCRBYFLOAT mykey field 0.1
HINCRBYFLOAT mykey field -5
HSET mykey field 5.0e3
HINCRBYFLOAT mykey field 2.0e2

Implementation details

The command is always propagated in the replication link and the Append Only
File as a [`HSET`]() operation, so that differences in the underlying floating point
math implementation will not be sources of inconsistency.

Return information

**RESP2:**

[Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): the value of the field after the increment operation.

**RESP3:**

[Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): The value of the field after the increment operation.


HKEYS

Summary: Returns all fields in a hash.

Overview

Returns all field names in the hash stored at `key`.

Examples

HSET myhash field1 "Hello"
HSET myhash field2 "World"
HKEYS myhash

Return information

**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): a list of fields in the hash, or an empty list when the key does not exist

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): a list of fields in the hash, or an empty list when the key does not exist.


HLEN

Summary: Returns the number of fields in a hash.

Overview

Returns the number of fields contained in the hash stored at `key`.

Examples

HSET myhash field1 "Hello"
HSET myhash field2 "World"
HLEN myhash

| 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): the number of fields in the hash, or 0 when the key does not exist.

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): the number of the fields in the hash, or 0 when the key does not exist.


HMGET

Summary: Returns the values of all fields in a hash.

Return information

**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): a list of values associated with the given fields, in the same order as they are requested.

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): a list of values associated with the given fields, in the same order as they are requested.


HMSET

Summary: Sets the values of multiple fields.

Overview

Sets the specified fields to their respective values in the hash stored at
`key`.
This command overwrites any specified fields already existing in the hash.
If `key` does not exist, a new key holding a hash is created.

Examples

HMSET myhash field1 "Hello" field2 "World"
HGET myhash field1
HGET myhash field2

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

Return information

**RESP2:**

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

**RESP3:**

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


HOTKEYS

Summary: A container for hotkeys tracking commands.

Overview

This is a container command for hotkeys tracking commands that provides a method for identifying hotkeys inside a Redis server during a specified tracking time period.

Hotkeys in this context are defined by two metrics:
* Percentage of CPU time spent on the key from the total time during the tracking period.
* Percentage of network bytes (input + output) used for the key from the total network bytes used by Redis during the tracking period.

Usage

The general workflow is for the user to initiate a hotkeys tracking process which should run for some time. The keys' metrics are recorded inside a probabilistic data structure, after which the user is able to fetch the top K metrics.

Available subcommands:

- [`HOTKEYS START`]() - Starts hotkeys tracking with specified metrics.
- [`HOTKEYS STOP`]() - Stops hotkeys tracking but preserves data.
- [`HOTKEYS GET`]() - Returns tracking results and metadata.
- [`HOTKEYS RESET`]() - Releases resources used for tracking.


HOTKEYS GET

Summary: Returns lists of top K hotkeys depending on metrics chosen in HOTKEYS START command.

Overview

Returns tracking results and metadata from the current or most recent hotkeys tracking session.

This command returns comprehensive information about the hotkeys tracking session, including:

- Tracking metadata (start time, duration, sample ratio, etc.)
- Performance statistics (CPU time, network bytes)
- Lists of top K hot keys sorted by the metrics specified in `HOTKEYS START`

The following metrics are collected for non-clustered as well as clustered Redis environments:

- `tracking-active` (integer): 1 if tracking is active, 0 if stopped
- `sample-ratio` (integer): The sampling ratio used during tracking
- `selected-slots` (array): [Array]() of select slots and slot ranges
- `all-commands-all-slots-us` (integer): CPU time in microseconds for all commands on all slots
- `net-bytes-all-commands-all-slots` (integer): Network bytes for all commands on all slots
- `collection-start-time-unix-ms` (integer): Unix timestamp in milliseconds when tracking started
- `collection-duration-ms` (integer): Duration of tracking in milliseconds
- `total-cpu-time-user-ms` (integer): User CPU time used in milliseconds (only when the `CPU` metric was specified with `HOTKEYS START`)
- `total-cpu-time-sys-ms` (integer): System CPU time used in milliseconds (only when the `CPU` metric was specified with `HOTKEYS START`)
- `total-net-bytes` (integer): Total network bytes processed (only when the `NET` metric was specified with `HOTKEYS START`)
- `by-cpu-time-us` (array): [Array]() of key-time pairs sorted by CPU time in microseconds (only when the `CPU` metric was specified with `HOTKEYS START`)
- `by-net-bytes` (array): [Array]() of key-bytes pairs sorted by network bytes (only when the `NET` metric was specified with `HOTKEYS START`)

The following additional results are collected only on clustered Redis environments, when `SLOTS` was used with `HOTKEYS START`:

- `sampled-commands-selected-slots-us` (integer): CPU time in milliseconds for sampled commands in selected slots (only when `SAMPLE` was used with `HOTKEYS START`)
- `all-commands-selected-slots-us` (integer): CPU time in milliseconds for all commands in selected slots
- `net-bytes-sampled-commands-selected-slots` (integer): Network bytes for sampled commands in selected slots (only when `SAMPLE` was used with `HOTKEYS START`)
- `net-bytes-all-commands-selected-slots` (integer): Network bytes for all commands on selected slots

Example (both `NET` and `CPU` metrics specified)

[code example]

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

Return information

**RESP2:**

One of the following:

- [Array reply]() when tracking data is available, containing an array of pairs of field names and values.
- [Null reply]() when no tracking has been started or data has been reset.

**RESP3:**

One of the following:

- [Array reply]() when tracking data is available, containing a [map]() of field names and values.
- [Null reply]() when no tracking has been started or data has been reset.

HOTKEYS GET
1)  1) "tracking-active"
    2) (integer) 0
    3) "sample-ratio"
    4) (integer) 1
    5) "selected-slots"
    6) 1) 1) (integer) 0
          2) (integer) 16383
    7) "all-commands-all-slots-us"
    8) (integer) 103
    9) "net-bytes-all-commands-all-slots"
   10) (integer) 2042
   11) "collection-start-time-unix-ms"
   12) (integer) 1770824933147
   13) "collection-duration-ms"
   14) (integer) 0
   15) "total-cpu-time-user-ms"
   16) (integer) 23
   17) "total-cpu-time-sys-ms"
   18) (integer) 7
   19) "total-net-bytes"
   20) (integer) 2038
   21) "by-cpu-time-us"
   22)  1) "hotkey_001_counter"
        2) (integer) 29
        3) "hotkey_001"
        4) (integer) 25
        5) "hotkey_001_hash"
        6) (integer) 11
        7) "hotkey_001_list"
        8) (integer) 9
        9) "hotkey_001_set"
       10) (integer) 9
   23) "by-net-bytes"
   24)  1) "hotkey_001"
        2) (integer) 446
        3) "hotkey_002"
        4) (integer) 328
        5) "hotkey_001_hash"
        6) (integer) 198
        7) "hotkey_001_set"
        8) (integer) 167
        9) "hotkey_001_counter"
       10) (integer) 116


HOTKEYS HELP

Summary: Returns helpful text about HOTKEYS commands and parameters.

Overview

Returns helpful text about `HOTKEYS` commands and parameters.

Return information

**RESP2:**

Returns an [array reply]() with the list of `HOTKEYS` subcommands and their descriptions.

**RESP3:**

Returns an [array reply]() with the list of `HOTKEYS` subcommands and their descriptions.


HOTKEYS RESET

Overview

Release the resources used for hotkey tracking.

This command can only be executed when hotkey tracking is stopped. It will return an error if tracking is currently active. Use [`HOTKEYS STOP`]() first to stop tracking, then use `HOTKEYS RESET` to free the allocated resources.

Return information

**RESP2:**

One of the following:

- [Simple string reply](): `OK` when resources are successfully released.
- [Simple error reply](): when tracking is currently active.

**RESP3:**

One of the following:

- [Simple string reply](): `OK` when resources are successfully released.
- [Simple error reply](): when tracking is currently active.


HOTKEYS START

Summary: Starts hotkeys tracking.

Overview

Starts hotkeys tracking with specified metrics.

This command initiates a hotkey tracking session. You must specify which metrics to track using the required `METRICS` parameter.
An error is returned if a tracking session is already in progress.

The tracking session continues until manually stopped with [`HOTKEYS STOP`]() or automatically stopped after the specified duration.

Arguments

METRICS count [CPU] [NET]

**Required.** Specifies which metrics to track and how many hotkeys to track.

- `count` - The number of metrics to collect (required).
- `CPU` - Track hotkeys by CPU time percentage (optional).
- `NET` - Track hotkeys by network bytes percentage (optional).

At least one of `CPU` or `NET` must be specified.

Optional arguments

COUNT

Specifies the value of K for the top-K hotkeys tracking.

DURATION

The duration in seconds for how long the hotkeys tracking should run. After this time period, tracking will automatically stop. If not specified, tracking continues until manually stopped with `HOTKEYS STOP`.

SAMPLE

Sampling ratio for probabilistic tracking. Each key is sampled with probability `1/ratio`. Higher values reduce performance impact but may miss some hotkeys. Lower values provide more accurate results but with higher performance cost.

SLOTS

Specifies which hash slots to track in a cluster environment. Takes a count followed by that many slot numbers. Only keys that hash to the specified slots will be tracked. Useful for tracking hotkeys on specific shards in a Redis cluster. Using `SLOTS` when not in cluster mode will result in an error.

Return information

**RESP2:**

One of the following:

- [Simple string]() reply: `OK` when tracking is successfully started.
- [Error reply](): when invalid parameters are provided.

**RESP3:**

One of the following:

- [Simple string]() reply: `OK` when tracking is successfully started.
- [Error reply](): when invalid parameters are provided.


HOTKEYS STOP

Summary: Stops hotkeys tracking.

Overview

Stops hotkeys tracking but preserves the collected data.

After stopping, the tracking data remains available through [`HOTKEYS GET`]() until [`HOTKEYS RESET`]() is called or a new tracking session is started.

Return information

**RESP2:**

One of the following:

- [Simple string reply](): `OK` when tracking is successfully stopped.
- [Simple error reply](): when tracking is not currently active.

**RESP3:**

One of the following:

- [Simple string reply](): `OK` when tracking is successfully stopped.
- [Simple error reply](): when tracking is not currently active.


HPERSIST

Summary: Removes the expiration time for each specified field

Overview

Remove the existing expiration on a hash key's field(s), turning the field(s) from _volatile_ (a field
with expiration set) to _persistent_ (a field that will never expire as no TTL (time to live)
is associated).

Examples

[code example]

| 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). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-1` if the field exists but has no associated expiration set.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `1` the expiration was removed.

**RESP3:**

* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-1` if the field exists but has no associated expiration set.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `1` the expiration was removed.

redis> HSET mykey field1 "hello" field2 "world"
(integer) 2
redis> HEXPIRE mykey 300 FIELDS 2 field1 field2
1) (integer) 1
2) (integer) 1
redis> HTTL mykey FIELDS 2 field1 field2
1) (integer) 283
2) (integer) 283
redis> HPERSIST mykey FIELDS 1 field2
1) (integer) 1
redis> HTTL mykey FIELDS 2 field1 field2
1) (integer) 268
2) (integer) -1


HPEXPIRE

Summary: Set expiration for hash fields using relative time to expire (milliseconds)

Overview

This command works like [`HEXPIRE`](), but the expiration of a field is
specified in milliseconds instead of seconds.

Options

The `HPEXPIRE` command supports a set of options:

* `NX` -- For each specified field, set expiration only when the field has no expiration.
* `XX` -- For each specified field, set expiration only when the field has an existing expiration.
* `GT` -- For each specified field, set expiration only when the new expiration is greater than current one.
* `LT` -- For each specified field, set expiration only when the new expiration is less than current one.

A non-volatile key is treated as an infinite TTL for the purposes of `GT` and `LT`.
The `NX`, `XX`, `GT`, and `LT` options are mutually exclusive.

Example

[code example]

Return information

**RESP2:**

One of the following:
* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `0` if the specified NX, XX, GT, or LT condition has not been met.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `1` if the expiration time was set/updated.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `2` when `HEXPIRE` or `HPEXPIRE` is called with 0 seconds or milliseconds, or when `HEXPIREAT` or `HPEXPIREAT` is called with a past Unix time in seconds or milliseconds.
* [Simple error reply](../../develop/reference/protocol-spec#simple-errors):
    - if parsing failed, mandatory arguments are missing, unknown arguments are specified, or argument values are of the wrong type or out of range.
    - if the provided key exists but is not a hash.

**RESP3:**

One of the following:
* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `0` if the specified NX, XX, GT, or LT condition has not been met.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `1` if the expiration time was set/updated.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `2` when `HEXPIRE` or `HPEXPIRE` is called with 0 seconds or milliseconds, or when `HEXPIREAT` or `HPEXPIREAT` is called with a past Unix time in seconds or milliseconds.
* [Simple error reply](../../develop/reference/protocol-spec#simple-errors):
    - if parsing failed, mandatory arguments are missing, unknown arguments are specified, or argument values are of the wrong type or out of range.
    - if the provided key exists but is not a hash.

redis> HSET mykey field1 "hello" field2 "world"
(integer) 2
redis> HPEXPIRE mykey 2000 FIELDS 2 field1 field2
1) (integer) 1
2) (integer) 1
redis> HGETALL mykey
(empty array)


HPEXPIREAT

Summary: Set expiration for hash fields using an absolute Unix timestamp (milliseconds)

Overview

`HPEXPIREAT` has the same effect and semantics as [`HEXPIREAT`](), but the Unix time at
which the field will expire is specified in milliseconds since Unix epoch instead of seconds.

Options

The `HPEXPIREAT` command supports a set of options:

* `NX` -- For each specified field, set expiration only when the field has no expiration.
* `XX` -- For each specified field, set expiration only when the field has an existing expiration.
* `GT` -- For each specified field, set expiration only when the new expiration is greater than current one.
* `LT` -- For each specified field, set expiration only when the new expiration is less than current one.

A non-volatile key is treated as an infinite TTL for the purposes of `GT` and `LT`.
The `NX`, `XX`, `GT`, and `LT` options are mutually exclusive.

Example

[code example]

Return information

redis> HSET mykey field1 "hello" field2 "world"
(integer) 2
redis> HPEXPIREAT mykey 1715704971000 FIELDS 2 field1 field2
1) (integer) 1
2) (integer) 1
redis> HPTTL mykey FIELDS 2 field1 field2
1) (integer) 303340
2) (integer) 303340


HPEXPIRETIME

Summary: Returns the expiration time of a hash field as a Unix timestamp, in msec.

Overview

`HPEXPIRETIME` has the same semantics as [`HEXPIRETIME`](), but returns the absolute Unix expiration timestamp in milliseconds since Unix epoch instead of seconds.

Examples

[code example]

Return information

**RESP2:**

* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-1` if the field exists but has no associated expiration set.
    - [Integer reply](../../develop/reference/protocol-spec#integers): the expiration (Unix timestamp) in milliseconds.

**RESP3:**

* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-1` if the field exists but has no associated expiration set.
    - [Integer reply](../../develop/reference/protocol-spec#integers): the expiration (Unix timestamp) in milliseconds.

redis> HSET mykey field1 "hello" field2 "world"
(integer) 2
redis> HEXPIRE mykey 300 FIELDS 2 field1 field2
1) (integer) 1
2) (integer) 1
redis> HPEXPIRETIME mykey FIELDS 2 field1 field2
1) (integer) 1715705913659
2) (integer) 1715705913659


HPTTL

Summary: Returns the TTL in milliseconds of a hash field.

Overview

Like [`HTTL`](), this command returns the remaining TTL (time to live) of a field that has an
expiration set, but in milliseconds instead of seconds.

Example

[code example]

Return information

**RESP2:**

* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-1` if the field exists but has no associated expiration set.
    - [Integer reply](../../develop/reference/protocol-spec#integers): the TTL in milliseconds.

**RESP3:**

* [Array reply](../../develop/reference/protocol-spec#arrays). For each field:
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-2` if no such field exists in the provided hash key, or the provided key does not exist.
    - [Integer reply](../../develop/reference/protocol-spec#integers): `-1` if the field exists but has no associated expiration set.
    - [Integer reply](../../develop/reference/protocol-spec#integers): the TTL in milliseconds.

redis> HPTTL no-key FIELDS 3 field1 field2 field3
(nil)
redis> HSET mykey field1 "hello" field2 "world"
(integer) 2
redis> HEXPIRE mykey 300 FIELDS 2 field1 field3
1) (integer) 1
2) (integer) -2
redis> HPTTL mykey FIELDS 3 field1 field2 field3
1) (integer) 292202
2) (integer) -1
3) (integer) -2


HRANDFIELD

Summary: Returns one or more random fields from a hash.

Overview

When called with just the `key` argument, return a random field from the hash value stored at `key`.

If the provided `count` argument is positive, return an array of **distinct fields**.
The array's length is either `count` or the hash's number of fields ([`HLEN`]()), whichever is lower.

If called with a negative `count`, the behavior changes and the command is allowed to return the **same field multiple times**.
In this case, the number of returned fields is the absolute value of the specified `count`.

The optional `WITHVALUES` modifier changes the reply so it includes the respective values of the randomly selected hash fields.

Examples

HSET coin heads obverse tails reverse edge null
HRANDFIELD coin
HRANDFIELD coin
HRANDFIELD coin -5 WITHVALUES

Specification of the behavior when count is passed

When the `count` argument is a positive value this command behaves as follows:

* No repeated fields are returned.
* If `count` is bigger than the number of fields in the hash, the command will only return the whole hash without additional fields.
* The order of fields in the reply is not truly random, so it is up to the client to shuffle them if needed.

When the `count` is a negative value, the behavior changes as follows:

* Repeating fields are possible.
* Exactly `count` fields, or an empty array if the hash is empty (non-existing key), are always returned.
* The order of fields in the reply is truly random.

Return information

**RESP2:**

Any of the following:
* [Nil reply](../../develop/reference/protocol-spec#bulk-strings): if the key doesn't exist
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): a single, randomly selected field when the `count` option is not used
* [Array reply](../../develop/reference/protocol-spec#arrays): a list containing `count` fields when the `count` option is used, or an empty array if the key does not exists.
* [Array reply](../../develop/reference/protocol-spec#arrays): a list of fields and their values when `count` and `WITHVALUES` were both used.

**RESP3:**

Any of the following:
* [Null reply](../../develop/reference/protocol-spec#nulls): if the key doesn't exist
* [Bulk string reply](../../develop/reference/protocol-spec#bulk-strings): a single, randomly selected field when the `count` option is not used
* [Array reply](../../develop/reference/protocol-spec#arrays): a list containing `count` fields when the `count` option is used, or an empty array if the key does not exists.
* [Array reply](../../develop/reference/protocol-spec#arrays): a list of fields and their values when `count` and `WITHVALUES` were both used.


HSCAN

Summary: Iterates over fields and values of a hash.

Overview

See [`SCAN`]() for `HSCAN` documentation.

Return information

**RESP2:**

[Array reply](../../develop/reference/protocol-spec#arrays): a two-element array.
* 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) of field/value pairs that were scanned. When the `NOVALUES` flag (since Redis 7.4) is used, only the field names are returned.

**RESP3:**

[Array reply](../../develop/reference/protocol-spec#arrays): a two-element array.
* 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) of field/value pairs that were scanned. When the `NOVALUES` flag (since Redis 7.4) is used, only the field names are returned.


HSET

Summary: Creates or modifies the value of a field in a hash.

Examples

#### Code Examples

Foundational: Set one or more field-value pairs in a hash using HSET (creates hash if needed, overwrites existing fields, returns count of new fields)

**Difficulty:** Beginner

**Commands:** HSET, HGET, HGETALL

**Complexity:**
- HSET: O(1)
- HGET: O(1)
- HGETALL: O(N)

**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:

HSET myhash field1 "Hello"
HGET myhash field1
HSET myhash field2 "Hi" field3 "World"
HGET myhash field2
HGET myhash field3
HGETALL myhash

| 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): the number of fields that were added.

**RESP3:**

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

> HSET myhash field1 "Hello"
(integer) 1
> HGET myhash field1
"Hello"
> HSET myhash field2 "Hi" field3 "World"
(integer) 2
> HGET myhash field2
"Hi"
> HGET myhash field3
"World"
> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "Hi"
5) "field3"
6) "World"

#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 hash with fields
    reply = redisCommand(c, "HSET %s %s %s %s %s",
        "myhash", "field1", "Hello", "field2", "World");
    freeReplyObject(reply);

    // Get multiple fields at once
    reply = redisCommand(c, "HMGET %s %s %s %s",
        "myhash", "field1", "field2", "nofield");

    printf("HMGET myhash field1 field2 nofield:\n");
    for (size_t i = 0; i < reply->elements; i++) {
        if (reply->element[i]->type == REDIS_REPLY_NIL) {
            printf("  [%zu]: null\n", i);
        } else {
            printf("  [%zu]: %s\n", i, reply->element[i]->str);
        }
    }
    // >>> [0]: Hello
    // >>> [1]: World
    // >>> [2]: null

    freeReplyObject(reply);

    redisFree(c);

    return 0;
}

bool hsetRes1 = db.HashSet("myhash", "field1", "Hello");
        RedisValue hsetRes2 = db.HashGet("myhash", "field1");
        Console.WriteLine(hsetRes2);    // >>> Hello

        db.HashSet(
            "myhash",
            [
                new("field2", "Hi"),
                new("field3", "World")
            ]
        );

        RedisValue hsetRes3 = db.HashGet("myhash", "field2");
        Console.WriteLine(hsetRes3);    // >>> Hi

        RedisValue hsetRes4 = db.HashGet("myhash", "field3");
        Console.WriteLine(hsetRes4);    // >>> World

        HashEntry[] hsetRes5 = db.HashGetAll("myhash");
        Console.WriteLine($"{string.Join(", ", hsetRes5.Select(h => $"{h.Name}: {h.Value}"))}");
        // >>> field1: Hello, field2: Hi, field3: World

res1, err := rdb.HSet(ctx, "myhash", "field1", "Hello").Result()

	if err != nil {
		panic(err)
	}

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

	res2, err := rdb.HGet(ctx, "myhash", "field1").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res2) // >>> Hello

	res3, err := rdb.HSet(ctx, "myhash",
		"field2", "Hi",
		"field3", "World",
	).Result()

	if err != nil {
		panic(err)
	}

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

	res4, err := rdb.HGet(ctx, "myhash", "field2").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res4) // >>> Hi

	res5, err := rdb.HGet(ctx, "myhash", "field3").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res5) // >>> World

	res6, err := rdb.HGetAll(ctx, "myhash").Result()

	if err != nil {
		panic(err)
	}

	keys := make([]string, 0, len(res6))

	for key, _ := range res6 {
		keys = append(keys, key)
	}

	sort.Strings(keys)

	for _, key := range keys {
		fmt.Printf("Key: %v, value: %v\n", key, res6[key])
	}
	// >>> Key: field1, value: Hello
	// >>> Key: field2, value: Hi
	// >>> Key: field3, value: World

CompletableFuture<Void> hSetExample = asyncCommands.hset("myhash", "field1", "Hello").thenCompose(res1 -> {
                System.out.println(res1); // >>> 1
                return asyncCommands.hget("myhash", "field1");
            }).thenCompose(res2 -> {
                System.out.println(res2); // >>> Hello
                Map<String, String> hSetExampleParams = new HashMap<>();
                hSetExampleParams.put("field2", "Hi");
                hSetExampleParams.put("field3", "World");
                return asyncCommands.hset("myhash", hSetExampleParams);
            }).thenCompose(res3 -> {
                System.out.println(res3); // >>> 2
                return asyncCommands.hget("myhash", "field2");
            }).thenCompose(res4 -> {
                System.out.println(res4); // >>> Hi
                return asyncCommands.hget("myhash", "field3");
            }).thenCompose(res5 -> {
                System.out.println(res5); // >>> World
                return asyncCommands.hgetall("myhash");
            }).thenAccept(res6 -> {
                System.out.println(res6);
                // >>> {field1=Hello, field2=Hi, field3=World}
            }).toCompletableFuture();

Mono<Boolean> hSetExample1 = reactiveCommands.hset("myhash", "field1", "Hello").doOnNext(result -> {
                System.out.println(result); // >>> True
            });

            hSetExample1.block();

            Mono<String> hSetExample2 = reactiveCommands.hget("myhash", "field1").doOnNext(result -> {
                System.out.println(result); // >>> Hello
            });

            hSetExample2.block();

            Map<String, String> hSetExampleParams = new HashMap<>();
            hSetExampleParams.put("field2", "Hi");
            hSetExampleParams.put("field3", "World");

            Mono<Long> hSetExample3 = reactiveCommands.hset("myhash", hSetExampleParams).doOnNext(result -> {
                System.out.println(result); // >>> 2
            });

            hSetExample3.block();

            Mono<String> hSetExample4 = reactiveCommands.hget("myhash", "field2").doOnNext(result -> {
                System.out.println(result); // >>> Hi
            });

            hSetExample4.block();

            Mono<String> hSetExample5 = reactiveCommands.hget("myhash", "field3").doOnNext(result -> {
                System.out.println(result); // >>> World
            });

            hSetExample5.block();

            Mono<Map<String, String>> hSetExample6 = reactiveCommands.hgetall("myhash").collectMap(
                    KeyValue::getKey, KeyValue::getValue
            ).doOnNext(result -> {
                System.out.println(result);
                // >>> {field1=Hello, field2=Hi, field3=World}
            });

Map<String, String> hSetExampleParams = new HashMap<>();
        hSetExampleParams.put("field1", "Hello");
        long hSetResult1 = jedis.hset("myhash", hSetExampleParams);
        System.out.println(hSetResult1);    // >>> 1

        String hSetResult2 = jedis.hget("myhash", "field1");
        System.out.println(hSetResult2);    // >>> Hello

        hSetExampleParams.clear();
        hSetExampleParams.put("field2", "Hi");
        hSetExampleParams.put("field3", "World");
        long hSetResult3 = jedis.hset("myhash",hSetExampleParams);
        System.out.println(hSetResult3);    // >>> 2

        String hSetResult4 = jedis.hget("myhash", "field2");
        System.out.println(hSetResult4);    // >>> Hi

        String hSetResult5 = jedis.hget("myhash", "field3");
        System.out.println(hSetResult5);    // >>> World

        Map<String, String> hSetResult6 = jedis.hgetAll("myhash");

        for (String key: hSetResult6.keySet()) {
            System.out.println("Key: " + key + ", Value: " + hSetResult6.get(key));
        }
        // >>> Key: field3, Value: World
        // >>> Key: field2, Value: Hi
        // >>> Key: field1, Value: Hello

const res1 = await client.hSet('myhash', 'field1', 'Hello')
console.log(res1) // 1

const res2 = await client.hGet('myhash', 'field1')
console.log(res2) // Hello

const res3 = await client.hSet(
  'myhash',
  {
    'field2': 'Hi',
    'field3': 'World'
  }
)
console.log(res3) // 2

const res4 = await client.hGet('myhash', 'field2')
console.log(res4) // Hi

const res5 = await client.hGet('myhash', 'field3')
console.log(res5) // World

const res6 = await client.hGetAll('myhash')
console.log(res6)

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

const redis = new Redis();

await redis.hset('myhash', { field1: 'Hello', field2: 'World' });

const hmgetResult = await redis.hmget('myhash', 'field1', 'field2', 'nofield');
console.log(hmgetResult); // >>> ['Hello', 'World', null]

redis.disconnect();

$hSetResult1 = $this->redis->hset('myhash', 'field1', 'Hello');
        echo "HSET myhash field1 Hello: " . $hSetResult1 . "\n"; // >>> 1

        $hSetResult2 = $this->redis->hget('myhash', 'field1');
        echo "HGET myhash field1: " . $hSetResult2 . "\n"; // >>> Hello

        $hSetResult3 = $this->redis->hmset('myhash', ['field2' => 'Hi', 'field3' => 'World']);
        echo "HMSET myhash field2 Hi field3 World: " . ($hSetResult3 ? 'OK' : 'FAIL') . "\n"; // >>> OK

        $hSetResult4 = $this->redis->hget('myhash', 'field2');
        echo "HGET myhash field2: " . $hSetResult4 . "\n"; // >>> Hi

        $hSetResult5 = $this->redis->hget('myhash', 'field3');
        echo "HGET myhash field3: " . $hSetResult5 . "\n"; // >>> World

        $hSetResult6 = $this->redis->hgetall('myhash');
        echo "HGETALL myhash: ";
        foreach ($hSetResult6 as $key => $value) {
            echo "Key: $key, Value: $value; ";
        }
        echo "\n";

res1 = r.hset("myhash", "field1", "Hello")
print(res1)
# >>> 1

res2 = r.hget("myhash", "field1")
print(res2)
# >>> Hello

res3 = r.hset("myhash", mapping={"field2": "Hi", "field3": "World"})
print(res3)
# >>> 2

res4 = r.hget("myhash", "field2")
print(res4)
# >>> Hi

res5 = r.hget("myhash", "field3")
print(res5)
# >>> World

res6 = r.hgetall("myhash")
print(res6)
# >>> { "field1": "Hello", "field2": "Hi", "field3": "World" }

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

        match r.hget("myhash", "field1").await {
            Ok(res2) => {
                let res2: Option<String> = res2;
                match res2 {
                    Some(value) => {
                        println!("{value}");    // >>> Hello
                    },
                    None => {
                        println!("None");
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }

        // Set multiple fields using hset_multiple
        let hash_fields = [
            ("field2", "Hi"),
            ("field3", "World"),
        ];

        if let Ok(res) = r.hset_multiple("myhash", &hash_fields).await {
            let res: String = res;
            println!("{res}");    // >>> OK
        }

        match r.hget("myhash", "field2").await {
            Ok(res4) => {
                let res4: Option<String> = res4;
                match res4 {
                    Some(value) => {
                        println!("{value}");    // >>> Hi
                    },
                    None => {
                        println!("None");
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }

        match r.hget("myhash", "field3").await {
            Ok(res5) => {
                let res5: Option<String> = res5;
                match res5 {
                    Some(value) => {
                        println!("{value}");    // >>> World
                    },
                    None => {
                        println!("None");
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }

        match r.hgetall("myhash").await {
            Ok(res6) => {
                let res6: HashMap<String, String> = res6;
                println!("{res6:?}");    // >>> {"field1": "Hello", "field2": "Hi", "field3": "World"}
            },
            Err(e) => {
                println!("Error getting all hash fields: {e}");
                return;
            }
        }

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

        match r.hget("myhash", "field1") {
            Ok(res2) => {
                let res2: Option<String> = res2;
                match res2 {
                    Some(value) => {
                        println!("{value}");    // >>> Hello
                    },
                    None => {
                        println!("None");
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }

        // Set multiple fields using hset_multiple
        let hash_fields = [
            ("field2", "Hi"),
            ("field3", "World"),
        ];

        if let Ok(res) = r.hset_multiple("myhash", &hash_fields) {
            let res: String = res;
            println!("{res}");    // >>> OK
        }

        match r.hget("myhash", "field2") {
            Ok(res4) => {
                let res4: Option<String> = res4;
                match res4 {
                    Some(value) => {
                        println!("{value}");    // >>> Hi
                    },
                    None => {
                        println!("None");
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }

        match r.hget("myhash", "field3") {
            Ok(res5) => {
                let res5: Option<String> = res5;
                match res5 {
                    Some(value) => {
                        println!("{value}");    // >>> World
                    },
                    None => {
                        println!("None");
                    }
                }
            },
            Err(e) => {
                println!("Error getting hash field: {e}");
                return;
            }
        }

        match r.hgetall("myhash") {
            Ok(res6) => {
                let res6: HashMap<String, String> = res6;
                println!("{res6:?}");    // >>> {"field1": "Hello", "field2": "Hi", "field3": "World"}
            },
            Err(e) => {
                println!("Error getting all hash fields: {e}");
                return;
            }
        }


HSETEX

Summary: Set the value of one or more fields of a given hash key, and optionally set their expiration.

Overview

Set the value of one or more fields of a given hash key and optionally
set their expiration time or time-to-live (TTL). If the given key already holds a value, it is overwritten and any previous TTLs associated with the key are discarded.

Options

The `HSETEX` command supports a set of options:

* `FNX` -- Only set the fields if none of them already exist.
* `FXX` -- Only set the fields if all of them already exist.
* `EX seconds` -- Set the specified expiration time in seconds.
* `PX milliseconds` -- Set the specified expiration time in milliseconds.
* `EXAT unix-time-seconds` -- Set the specified Unix time in seconds at which the fields will expire.
* `PXAT unix-time-milliseconds` -- Set the specified Unix time in milliseconds at which the fields will expire.
* `KEEPTTL` -- Retain the TTL associated with the fields.

The `EX`, `PX`, `EXAT`, `PXAT`, and `KEEPTTL` options are mutually exclusive.

Example

[code example]

Return information

**RESP2:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): `0` if no fields were set.
* [Integer reply](../../develop/reference/protocol-spec#integers): `1` if all the fields wereset.

**RESP3:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): `0` if no fields were set.
* [Integer reply](../../develop/reference/protocol-spec#integers): `1` if all the fields wereset.

redis> HSETEX mykey EXAT 1740470400 FIELDS 2 field1 "Hello" field2 "World"
(integer) 1
redis> HTTL mykey FIELDS 2 field1 field2
1) (integer) 55627
2) (integer) 55627
redis> HSETEX mykey FNX EX 60 FIELDS 2 field1 "Hello" field2 "World"
(integer) 0
redis> HSETEX mykey FXX EX 60 KEEPTTL FIELDS 2 field1 "hello" field2 "world"
(error) ERR Only one of EX, PX, EXAT, PXAT or KEEPTTL arguments can be specified
redis> HSETEX mykey FXX KEEPTTL FIELDS 2 field1 "hello" field2 "world"
(integer) 1
redis> HTTL mykey FIELDS 2 field1 field2
1) (integer) 55481
2) (integer) 55481


HSETNX

Summary: Sets the value of a field in a hash only when the field doesn't exist.

Overview

Sets `field` in the hash stored at `key` to `value`, only if `field` does not
yet exist.
If `key` does not exist, a new key holding a hash is created.
If `field` already exists, this operation has no effect.

Examples

HSETNX myhash field "Hello"
HSETNX myhash field "World"
HGET myhash field

Return information

**RESP2:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): `0` if the field already exists in the hash and no operation was performed.
* [Integer reply](../../develop/reference/protocol-spec#integers): `1` if the field is a new field in the hash and the value was set.

**RESP3:**

One of the following:
* [Integer reply](../../develop/reference/protocol-spec#integers): `0` if the field already exists in the hash and no operation was performed.
* [Integer reply](../../develop/reference/protocol-spec#integers): `1` if the field is a new field in the hash and the value was set.


HSTRLEN

Summary: Returns the length of the value of a field.

Overview

Returns the string length of the value associated with `field` in the hash stored at `key`. If the `key` or the `field` do not exist, 0 is returned.

Examples

HSET myhash f1 HelloWorld f2 99 f3 -256
HSTRLEN myhash f1
HSTRLEN myhash f2
HSTRLEN myhash f3

Return information

**RESP2:**

[Integer reply](../../develop/reference/protocol-spec#integers): the string length of the value associated with the _field_, or zero when the _field_ isn't present in the hash or the _key_ doesn't exist at all.

**RESP3:**

[Integer reply](../../develop/reference/protocol-spec#integers): the string length of the value associated with the _field_, or zero when the _field_ isn't present in the hash or the _key_ doesn't exist at all.