Redis hashes

Introduction to Redis hashes

Hash command summary (view reference, 28 commands)

Redis hashes are record types structured as collections of field-value pairs. You can use hashes to represent basic objects and to store groupings of counters, among other things.

Foundational: Set and retrieve hash fields using HSET and HGET (overwrites existing field values)
HSET bike:1 model Deimos brand Ergonom type 'Enduro bikes' price 4972 HGET bike:1 model HGET bike:1 price HGETALL bike:1
res1 = r.hset(
    "bike:1",
    mapping={
        "model": "Deimos",
        "brand": "Ergonom",
        "type": "Enduro bikes",
        "price": 4972,
    },
)
print(res1)
# >>> 4

res2 = r.hget("bike:1", "model")
print(res2)
# >>> 'Deimos'

res3 = r.hget("bike:1", "price")
print(res3)
# >>> '4972'

res4 = r.hgetall("bike:1")
print(res4)
# >>> {'model': 'Deimos', 'brand': 'Ergonom', 'type': 'Enduro bikes', 'price': '4972'}

const res1 = await client.hSet(
  'bike:1',
  {
    'model': 'Deimos',
    'brand': 'Ergonom',
    'type': 'Enduro bikes',
    'price': 4972,
  }
)
console.log(res1) // 4

const res2 = await client.hGet('bike:1', 'model')
console.log(res2)  // 'Deimos'

const res3 = await client.hGet('bike:1', 'price')
console.log(res3)  // '4972'

const res4 = await client.hGetAll('bike:1')
console.log(res4)  
/*
{
  brand: 'Ergonom',
  model: 'Deimos',
  price: '4972',
  type: 'Enduro bikes'
}
*/
      Map<String, String> bike1 = new HashMap<>();
      bike1.put("model", "Deimos");
      bike1.put("brand", "Ergonom");
      bike1.put("type", "Enduro bikes");
      bike1.put("price", "4972");

      Long res1 = jedis.hset("bike:1", bike1);
      System.out.println(res1); // 4

      String res2 = jedis.hget("bike:1", "model");
      System.out.println(res2); // Deimos

      String res3 = jedis.hget("bike:1", "price");
      System.out.println(res3); // 4972

      Map<String, String> res4 = jedis.hgetAll("bike:1");
      System.out.println(res4); // {type=Enduro bikes, brand=Ergonom, price=4972, model=Deimos}
            Map<String, String> bike1 = new HashMap<>();
            bike1.put("model", "Deimos");
            bike1.put("brand", "Ergonom");
            bike1.put("type", "Enduro bikes");
            bike1.put("price", "4972");

            CompletableFuture<Void> setGetAll = asyncCommands.hset("bike:1", bike1).thenCompose(res1 -> {
                System.out.println(res1); // >>> 4
                return asyncCommands.hget("bike:1", "model");
            }).thenCompose(res2 -> {
                System.out.println(res2); // >>> Deimos
                return asyncCommands.hget("bike:1", "price");
            }).thenCompose(res3 -> {
                System.out.println(res3); // >>> 4972
                return asyncCommands.hgetall("bike:1");
            })
                    .thenAccept(System.out::println)
                    // >>> {type=Enduro bikes, brand=Ergonom, price=4972, model=Deimos}
                    .toCompletableFuture();
            Map<String, String> bike1 = new HashMap<>();
            bike1.put("model", "Deimos");
            bike1.put("brand", "Ergonom");
            bike1.put("type", "Enduro bikes");
            bike1.put("price", "4972");

            Mono<Long> setGetAll = reactiveCommands.hset("bike:1", bike1).doOnNext(result -> {
                System.out.println(result); // >>> 4
            });

            setGetAll.block();

            Mono<String> getModel = reactiveCommands.hget("bike:1", "model").doOnNext(result -> {
                System.out.println(result); // >>> Deimos
            });

            Mono<String> getPrice = reactiveCommands.hget("bike:1", "price").doOnNext(result -> {
                System.out.println(result); // >>> 4972
            });

            Mono<List<KeyValue<String, String>>> getAll = reactiveCommands.hgetall("bike:1").collectList().doOnNext(result -> {
                System.out.println(result);
                // >>> [KeyValue[type, Enduro bikes], KeyValue[brand, Ergonom],
                // KeyValue[price, 4972], KeyValue[model, Deimos]]
            });
	hashFields := []string{
		"model", "Deimos",
		"brand", "Ergonom",
		"type", "Enduro bikes",
		"price", "4972",
	}

	res1, err := rdb.HSet(ctx, "bike:1", hashFields).Result()

	if err != nil {
		panic(err)
	}

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

	res2, err := rdb.HGet(ctx, "bike:1", "model").Result()

	if err != nil {
		panic(err)
	}

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

	res3, err := rdb.HGet(ctx, "bike:1", "price").Result()

	if err != nil {
		panic(err)
	}

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

	cmdReturn := rdb.HGetAll(ctx, "bike:1")
	res4, err := cmdReturn.Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res4)
	// >>> map[brand:Ergonom model:Deimos price:4972 type:Enduro bikes]

	type BikeInfo struct {
		Model string `redis:"model"`
		Brand string `redis:"brand"`
		Type  string `redis:"type"`
		Price int    `redis:"price"`
	}

	var res4a BikeInfo

	if err := cmdReturn.Scan(&res4a); err != nil {
		panic(err)
	}

	fmt.Printf("Model: %v, Brand: %v, Type: %v, Price: $%v\n",
		res4a.Model, res4a.Brand, res4a.Type, res4a.Price)
	// >>> Model: Deimos, Brand: Ergonom, Type: Enduro bikes, Price: $4972
        db.HashSet("bike:1", [
            new("model", "Deimos"),
            new("brand", "Ergonom"),
            new("type", "Enduro bikes"),
            new("price", 4972)
        ]);

        Console.WriteLine("Hash Created");
        // Hash Created

        var model = db.HashGet("bike:1", "model");
        Console.WriteLine($"Model: {model}");
        // Model: Deimos

        var price = db.HashGet("bike:1", "price");
        Console.WriteLine($"Price: {price}");
        // Price: 4972

        var bike = db.HashGetAll("bike:1");
        Console.WriteLine("bike:1");
        Console.WriteLine(string.Join("\n", bike.Select(b => $"{b.Name}: {b.Value}")));
        // Bike:1:
        // model: Deimos
        // brand: Ergonom
        // type: Enduro bikes
        // price: 4972
        $res1 = $r->hmset('bike:1', [
            'model' => 'Deimos',
            'brand' => 'Ergonom',
            'type' => 'Enduro bikes',
            'price' => 4972,
        ]);

        echo $res1 . PHP_EOL;
        // >>> 4

        $res2 = $r->hget('bike:1', 'model');
        echo $res2 . PHP_EOL;
        // >>> Deimos

        $res3 = $r->hget('bike:1', 'price');
        echo $res3 . PHP_EOL;
        // >>> 4972

        $res4 = $r->hgetall('bike:1');
        echo json_encode($res3) . PHP_EOL;
        // >>> {"name":"Deimos","brand":"Ergonom","type":"Enduro bikes","price":"4972"}
res1 = r.hset('bike:1', {
  'model' => 'Deimos',
  'brand' => 'Ergonom',
  'type' => 'Enduro bikes',
  'price' => 4972
})
puts res1 # 4

res2 = r.hget('bike:1', 'model')
puts res2 # Deimos

res3 = r.hget('bike:1', 'price')
puts res3 # 4972

res4 = r.hgetall('bike:1')
puts res4.inspect
# {"model"=>"Deimos", "brand"=>"Ergonom", "type"=>"Enduro bikes", "price"=>"4972"}
        let hash_fields = [
            ("model", "Deimos"),
            ("brand", "Ergonom"),
            ("type", "Enduro bikes"),
            ("price", "4972"),
        ];

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

        match r.hget("bike:1", "model") {
            Ok(res) => {
                let res: String = res;
                println!("{res}");   // >>> Deimos
            },
            Err(e) => {
                println!("Error getting bike:1 model: {e}");
                return;
            }
        };

        match r.hget("bike:1", "price") {
            Ok(res) => {
                let res: String = res;
                println!("{res}");   // >>> 4972
            },
            Err(e) => {
                println!("Error getting bike:1 price: {e}");
                return;
            }
        };

        match r.hgetall("bike:1") {
            Ok(res) => {
                let res: Vec<(String, String)> = res;
                println!("{res:?}");
                // >>> [("model", "Deimos"), ("brand", "Ergonom"), ("type", "Enduro bikes"), ("price", "4972")]
            },
            Err(e) => {
                println!("Error getting bike:1: {e}");
                return;
            }
        };
        let hash_fields = [
            ("model", "Deimos"),
            ("brand", "Ergonom"),
            ("type", "Enduro bikes"),
            ("price", "4972"),
        ];

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

        match r.hget("bike:1", "model").await {
            Ok(res) => {
                let res: String = res;
                println!("{res}");   // >>> Deimos
            },
            Err(e) => {
                println!("Error getting bike:1 model: {e}");
                return;
            }
        };

        match r.hget("bike:1", "price").await {
            Ok(res) => {
                let res: String = res;
                println!("{res}");   // >>> 4972
            },
            Err(e) => {
                println!("Error getting bike:1 price: {e}");
                return;
            }
        };

        match r.hgetall("bike:1").await {
            Ok(res) => {
                let res: Vec<(String, String)> = res;
                println!("{res:?}");
                // >>> [("model", "Deimos"), ("brand", "Ergonom"), ("type", "Enduro bikes"), ("price", "4972")]
            },
            Err(e) => {
                println!("Error getting bike:1: {e}");
                return;
            }
        };

While hashes are handy to represent objects, actually the number of fields you can put inside a hash has no practical limits (other than available memory), so you can use hashes in many different ways inside your application.

The command HSET sets multiple fields of the hash, while HGET retrieves a single field. HMGET is similar to HGET but returns an array of values:

Retrieve multiple field values from a hash using HMGET when you need to reduce round trips to the server
DEL bike:1 HSET bike:1 model Deimos brand Ergonom type 'Enduro bikes' price 4972 HMGET bike:1 model price no-such-field
# Recreate the bike:1 hash so this example runs on its own.
r.delete("bike:1")
r.hset(
    "bike:1",
    mapping={
        "model": "Deimos",
        "brand": "Ergonom",
        "type": "Enduro bikes",
        "price": 4972,
    },
)

res5 = r.hmget("bike:1", ["model", "price"])
print(res5)
# >>> ['Deimos', '4972']
// Recreate the bike:1 hash so this example runs on its own.
await client.del('bike:1')
await client.hSet(
  'bike:1',
  {
    'model': 'Deimos',
    'brand': 'Ergonom',
    'type': 'Enduro bikes',
    'price': 4972,
  }
)

const res5 = await client.hmGet('bike:1', ['model', 'price'])
console.log(res5)  // ['Deimos', '4972']
      // Recreate the bike:1 hash so this example runs on its own.
      jedis.del("bike:1");
      jedis.hset("bike:1", bike1);

      List<String> res5 = jedis.hmget("bike:1", "model", "price");
      System.out.println(res5); // [Deimos, 4972]
            // Recreate the bike:1 hash so this example runs on its own.
            CompletableFuture<Void> hmGet = setGetAll
                    .thenCompose(res4 -> asyncCommands.del("bike:1"))
                    .thenCompose(delRes -> asyncCommands.hset("bike:1", bike1))
                    .thenCompose(hsetRes -> asyncCommands.hmget("bike:1", "model", "price"))
                    .thenAccept(System.out::println)
                    // [KeyValue[model, Deimos], KeyValue[price, 4972]]
                    .toCompletableFuture();
            // Recreate the bike:1 hash so this example runs on its own.
            Mono<List<KeyValue<String, String>>> hmGet = reactiveCommands.del("bike:1")
                    .then(reactiveCommands.hset("bike:1", bike1))
                    .then(reactiveCommands.hmget("bike:1", "model", "price").collectList())
                    .doOnNext(result -> {
                        System.out.println(result);
                        // >>> [KeyValue[model, Deimos], KeyValue[price, 4972]]
                    });
	// Recreate the bike:1 hash so this example runs on its own.
	rdb.Del(ctx, "bike:1")
	hashFields := []string{
		"model", "Deimos",
		"brand", "Ergonom",
		"type", "Enduro bikes",
		"price", "4972",
	}
	rdb.HSet(ctx, "bike:1", hashFields)

	cmdReturn := rdb.HMGet(ctx, "bike:1", "model", "price")
	res5, err := cmdReturn.Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res5) // >>> [Deimos 4972]

	type BikeInfo struct {
		Model string `redis:"model"`
		Brand string `redis:"-"`
		Type  string `redis:"-"`
		Price int    `redis:"price"`
	}

	var res5a BikeInfo

	if err := cmdReturn.Scan(&res5a); err != nil {
		panic(err)
	}

	fmt.Printf("Model: %v, Price: $%v\n", res5a.Model, res5a.Price)
	// >>> Model: Deimos, Price: $4972
        // Recreate the bike:1 hash so this example runs on its own.
        db.KeyDelete("bike:1");
        db.HashSet("bike:1", [
            new("model", "Deimos"),
            new("brand", "Ergonom"),
            new("type", "Enduro bikes"),
            new("price", 4972)
        ]);

        var values = db.HashGet("bike:1", ["model", "price"]);
        Console.WriteLine(string.Join(" ", values));
        // Deimos 4972
        // Recreate the bike:1 hash so this example runs on its own.
        $r->del('bike:1');
        $r->hmset('bike:1', [
            'model' => 'Deimos',
            'brand' => 'Ergonom',
            'type' => 'Enduro bikes',
            'price' => 4972,
        ]);

        $res5 = $r->hmget('bike:1', ['model', 'price']);
        echo json_encode($res5) . PHP_EOL;
        // >>> ["Deimos","4972"]
# Recreate the bike:1 hash so this example runs on its own.
r.del('bike:1')
r.hset('bike:1', {
  'model' => 'Deimos',
  'brand' => 'Ergonom',
  'type' => 'Enduro bikes',
  'price' => 4972
})

res5 = r.hmget('bike:1', 'model', 'price', 'no-such-field')
puts res5.inspect # ["Deimos", "4972", nil]
        // Recreate the bike:1 hash so this example runs on its own.
        let _: () = r.del("bike:1").expect("Failed to del");
        let _: () = r.hset_multiple(
            "bike:1",
            &[("model", "Deimos"), ("brand", "Ergonom"), ("type", "Enduro bikes"), ("price", "4972")],
        ).expect("Failed to hset");

        match r.hmget("bike:1", &["model", "price"]) {
            Ok(res) => {
                let res: Vec<String> = res;
                println!("{res:?}");   // >>> ["Deimos", "4972"]
            },
            Err(e) => {
                println!("Error getting bike:1: {e}");
                return;
            }
        };
        // Recreate the bike:1 hash so this example runs on its own.
        let _: () = r.del("bike:1").await.expect("Failed to del");
        let _: () = r.hset_multiple(
            "bike:1",
            &[("model", "Deimos"), ("brand", "Ergonom"), ("type", "Enduro bikes"), ("price", "4972")],
        ).await.expect("Failed to hset");

        match r.hmget("bike:1", &["model", "price"]).await {
            Ok(res) => {
                let res: Vec<String> = res;
                println!("{res:?}");   // >>> ["Deimos", "4972"]
            },
            Err(e) => {
                println!("Error getting bike:1: {e}");
                return;
            }
        };

There are commands that are able to perform operations on individual fields as well, like HINCRBY:

Increment hash field values for counters using HINCRBY (creates field if missing, initializes to 0)
DEL bike:1 HSET bike:1 model Deimos brand Ergonom type 'Enduro bikes' price 4972 HINCRBY bike:1 price 100 HINCRBY bike:1 price -100
# Recreate the bike:1 hash so this example runs on its own.
r.delete("bike:1")
r.hset(
    "bike:1",
    mapping={
        "model": "Deimos",
        "brand": "Ergonom",
        "type": "Enduro bikes",
        "price": 4972,
    },
)

res6 = r.hincrby("bike:1", "price", 100)
print(res6)
# >>> 5072
res7 = r.hincrby("bike:1", "price", -100)
print(res7)
# >>> 4972
// Recreate the bike:1 hash so this example runs on its own.
await client.del('bike:1')
await client.hSet(
  'bike:1',
  {
    'model': 'Deimos',
    'brand': 'Ergonom',
    'type': 'Enduro bikes',
    'price': 4972,
  }
)

const res6 = await client.hIncrBy('bike:1', 'price', 100)
console.log(res6)  // 5072
const res7 = await client.hIncrBy('bike:1', 'price', -100)
console.log(res7)  // 4972
      // Recreate the bike:1 hash so this example runs on its own.
      jedis.del("bike:1");
      jedis.hset("bike:1", bike1);

      Long res6 = jedis.hincrBy("bike:1", "price", 100);
      System.out.println(res6); // 5072
      Long res7 = jedis.hincrBy("bike:1", "price", -100);
      System.out.println(res7); // 4972
            // Recreate the bike:1 hash so this example runs on its own.
            CompletableFuture<Void> hIncrBy = hmGet
                    .thenCompose(r -> asyncCommands.del("bike:1"))
                    .thenCompose(delRes -> asyncCommands.hset("bike:1", bike1))
                    .thenCompose(hsetRes -> asyncCommands.hincrby("bike:1", "price", 100))
                    .thenCompose(res6 -> {
                        System.out.println(res6); // >>> 5072
                        return asyncCommands.hincrby("bike:1", "price", -100);
                    })
                    .thenAccept(System.out::println)
                    // >>> 4972
                    .toCompletableFuture();
            // Recreate the bike:1 hash so this example runs on its own.
            Mono<Void> hIncrBy = reactiveCommands.del("bike:1")
                    .then(reactiveCommands.hset("bike:1", bike1))
                    .then(reactiveCommands.hincrby("bike:1", "price", 100)).doOnNext(result -> {
                System.out.println(result); // >>> 5072
            }).flatMap(v -> reactiveCommands.hincrby("bike:1", "price", -100)).doOnNext(result -> {
                System.out.println(result); // >>> 4972
            }).then();
	// Recreate the bike:1 hash so this example runs on its own.
	rdb.Del(ctx, "bike:1")
	hashFields := []string{
		"model", "Deimos",
		"brand", "Ergonom",
		"type", "Enduro bikes",
		"price", "4972",
	}
	rdb.HSet(ctx, "bike:1", hashFields)

	res6, err := rdb.HIncrBy(ctx, "bike:1", "price", 100).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res6) // >>> 5072

	res7, err := rdb.HIncrBy(ctx, "bike:1", "price", -100).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res7) // >>> 4972
        // Recreate the bike:1 hash so this example runs on its own.
        db.KeyDelete("bike:1");
        db.HashSet("bike:1", [
            new("model", "Deimos"),
            new("brand", "Ergonom"),
            new("type", "Enduro bikes"),
            new("price", 4972)
        ]);

        var newPrice = db.HashIncrement("bike:1", "price", 100);
        Console.WriteLine($"New price: {newPrice}");
        // New price: 5072

        newPrice = db.HashIncrement("bike:1", "price", -100);
        Console.WriteLine($"New price: {newPrice}");
        // New price: 4972
        // Recreate the bike:1 hash so this example runs on its own.
        $r->del('bike:1');
        $r->hmset('bike:1', [
            'model' => 'Deimos',
            'brand' => 'Ergonom',
            'type' => 'Enduro bikes',
            'price' => 4972,
        ]);

        $res6 = $r->hincrby('bike:1', 'price', 100);
        echo $res6 . PHP_EOL;
        // >>> 5072

        $res7 = $r->hincrby('bike:1', 'price', -100);
        echo $res7 . PHP_EOL;
        // >>> 4972
# Recreate the bike:1 hash so this example runs on its own.
r.del('bike:1')
r.hset('bike:1', {
  'model' => 'Deimos',
  'brand' => 'Ergonom',
  'type' => 'Enduro bikes',
  'price' => 4972
})

res6 = r.hincrby('bike:1', 'price', 100)
puts res6 # 5072

res7 = r.hincrby('bike:1', 'price', -100)
puts res7 # 4972
        // Recreate the bike:1 hash so this example runs on its own.
        let _: () = r.del("bike:1").expect("Failed to del");
        let _: () = r.hset_multiple(
            "bike:1",
            &[("model", "Deimos"), ("brand", "Ergonom"), ("type", "Enduro bikes"), ("price", "4972")],
        ).expect("Failed to hset");

        if let Ok(res) = r.hincr("bike:1", "price", 100) {
            let res: i32 = res;
            println!("{res}");    // >>> 5072
        }

        if let Ok(res) = r.hincr("bike:1", "price", -100) {
            let res: i32 = res;
            println!("{res}");    // >>> 4972
        }
        // Recreate the bike:1 hash so this example runs on its own.
        let _: () = r.del("bike:1").await.expect("Failed to del");
        let _: () = r.hset_multiple(
            "bike:1",
            &[("model", "Deimos"), ("brand", "Ergonom"), ("type", "Enduro bikes"), ("price", "4972")],
        ).await.expect("Failed to hset");

        if let Ok(res) = r.hincr("bike:1", "price", 100).await {
            let res: i32 = res;
            println!("{res}");    // >>> 5072
        }

        if let Ok(res) = r.hincr("bike:1", "price", -100).await {
            let res: i32 = res;
            println!("{res}");    // >>> 4972
        }

You can find the full list of hash commands in the documentation.

It is worth noting that small hashes (i.e., a few elements with small values) are encoded in special way in memory that make them very memory efficient.

Examples

  • Store counters for the number of times bike:1 has been ridden, has crashed, or has changed owners:
    Practical pattern: Combine HINCRBY and HMGET to track multiple counters when you need atomic updates across multiple fields
    HINCRBY bike:1:stats rides 1 HINCRBY bike:1:stats rides 1 HINCRBY bike:1:stats rides 1 HINCRBY bike:1:stats crashes 1 HINCRBY bike:1:stats owners 1 HGET bike:1:stats rides HMGET bike:1:stats owners crashes
    res11 = r.hincrby("bike:1:stats", "rides", 1)
    print(res11)
    # >>> 1
    res12 = r.hincrby("bike:1:stats", "rides", 1)
    print(res12)
    # >>> 2
    res13 = r.hincrby("bike:1:stats", "rides", 1)
    print(res13)
    # >>> 3
    res14 = r.hincrby("bike:1:stats", "crashes", 1)
    print(res14)
    # >>> 1
    res15 = r.hincrby("bike:1:stats", "owners", 1)
    print(res15)
    # >>> 1
    res16 = r.hget("bike:1:stats", "rides")
    print(res16)
    # >>> 3
    res17 = r.hmget("bike:1:stats", ["crashes", "owners"])
    print(res17)
    # >>> ['1', '1']
    
    import assert from 'assert';
    import { createClient } from 'redis';
    
    const client = createClient();
    await client.connect();
    const res1 = await client.hSet(
      'bike:1',
      {
        'model': 'Deimos',
        'brand': 'Ergonom',
        'type': 'Enduro bikes',
        'price': 4972,
      }
    )
    console.log(res1) // 4
    
    const res2 = await client.hGet('bike:1', 'model')
    console.log(res2)  // 'Deimos'
    
    const res3 = await client.hGet('bike:1', 'price')
    console.log(res3)  // '4972'
    
    const res4 = await client.hGetAll('bike:1')
    console.log(res4)  
    /*
    {
      brand: 'Ergonom',
      model: 'Deimos',
      price: '4972',
      type: 'Enduro bikes'
    }
    */
    
    
    // Recreate the bike:1 hash so this example runs on its own.
    await client.del('bike:1')
    await client.hSet(
      'bike:1',
      {
        'model': 'Deimos',
        'brand': 'Ergonom',
        'type': 'Enduro bikes',
        'price': 4972,
      }
    )
    
    const res5 = await client.hmGet('bike:1', ['model', 'price'])
    console.log(res5)  // ['Deimos', '4972']
    
    
    // Recreate the bike:1 hash so this example runs on its own.
    await client.del('bike:1')
    await client.hSet(
      'bike:1',
      {
        'model': 'Deimos',
        'brand': 'Ergonom',
        'type': 'Enduro bikes',
        'price': 4972,
      }
    )
    
    const res6 = await client.hIncrBy('bike:1', 'price', 100)
    console.log(res6)  // 5072
    const res7 = await client.hIncrBy('bike:1', 'price', -100)
    console.log(res7)  // 4972
    
    
    const res11 = await client.hIncrBy('bike:1:stats', 'rides', 1)
    console.log(res11)  // 1
    const res12 = await client.hIncrBy('bike:1:stats', 'rides', 1)
    console.log(res12)  // 2
    const res13 = await client.hIncrBy('bike:1:stats', 'rides', 1)
    console.log(res13)  // 3
    const res14 = await client.hIncrBy('bike:1:stats', 'crashes', 1)
    console.log(res14)  // 1
    const res15 = await client.hIncrBy('bike:1:stats', 'owners', 1)
    console.log(res15)  // 1
    const res16 = await client.hGet('bike:1:stats', 'rides')
    console.log(res16)  // 3
    const res17 = await client.hmGet('bike:1:stats', ['crashes', 'owners'])
    console.log(res17)  // ['1', '1']
    
    
    await client.del('sensor:sensor1')
    await client.hSet('sensor:sensor1', { 'air_quality': 256, 'battery_level': 89 })
    
    // Set a TTL of 60 seconds on two fields of the hash.
    const res18 = await client.hExpire('sensor:sensor1', ['air_quality', 'battery_level'], 60)
    console.log(res18)  // [1, 1]
    
    // Retrieve the remaining TTL for those fields.
    const res19 = await client.hTTL('sensor:sensor1', ['air_quality', 'battery_level'])
    console.log(res19)  // [60, 60] (or close to 60)
    
    
    await client.del('sensor:sensor1')
    await client.hSet('sensor:sensor1', { 'air_quality': 256, 'battery_level': 89 })
    
    // Set the TTL of the 'air_quality' field in milliseconds.
    const res20 = await client.hpExpire('sensor:sensor1', ['air_quality'], 60000)
    console.log(res20)  // [1]
    
    // Retrieve the remaining TTL in milliseconds.
    const res21 = await client.hpTTL('sensor:sensor1', ['air_quality'])
    console.log(res21)  // [59994] (your actual value may vary)
    
    
    await client.del('sensor:sensor1')
    await client.hSet('sensor:sensor1', { 'air_quality': 256, 'battery_level': 89 })
    
    // Set the expiration of 'air_quality' to a Unix time 24 hours from now.
    const expireAt = Math.floor(Date.now() / 1000) + 24 * 60 * 60
    const res22 = await client.hExpireAt('sensor:sensor1', ['air_quality'], expireAt)
    console.log(res22)  // [1]
    
    // Retrieve the expiration time as a Unix timestamp in seconds.
    const res23 = await client.hExpireTime('sensor:sensor1', ['air_quality'])
    console.log(res23)  // [1717668041] (your actual value will vary)
    
    
          Long res8 = jedis.hincrBy("bike:1:stats", "rides", 1);
          System.out.println(res8); // 1
          Long res9 = jedis.hincrBy("bike:1:stats", "rides", 1);
          System.out.println(res9); // 2
          Long res10 = jedis.hincrBy("bike:1:stats", "rides", 1);
          System.out.println(res10); // 3
          Long res11 = jedis.hincrBy("bike:1:stats", "crashes", 1);
          System.out.println(res11); // 1
          Long res12 = jedis.hincrBy("bike:1:stats", "owners", 1);
          System.out.println(res12); // 1
          String res13 = jedis.hget("bike:1:stats", "rides");
          System.out.println(res13); // 3
          List<String> res14 = jedis.hmget("bike:1:stats", "crashes", "owners");
          System.out.println(res14); // [1, 1]
    
                CompletableFuture<Void> incrByGetMget = asyncCommands.hincrby("bike:1:stats", "rides", 1).thenCompose(res7 -> {
                    System.out.println(res7); // >>> 1
                    return asyncCommands.hincrby("bike:1:stats", "rides", 1);
                }).thenCompose(res8 -> {
                    System.out.println(res8); // >>> 2
                    return asyncCommands.hincrby("bike:1:stats", "rides", 1);
                }).thenCompose(res9 -> {
                    System.out.println(res9); // >>> 3
                    return asyncCommands.hincrby("bike:1:stats", "crashes", 1);
                }).thenCompose(res10 -> {
                    System.out.println(res10); // >>> 1
                    return asyncCommands.hincrby("bike:1:stats", "owners", 1);
                }).thenCompose(res11 -> {
                    System.out.println(res11); // >>> 1
                    return asyncCommands.hget("bike:1:stats", "rides");
                }).thenCompose(res12 -> {
                    System.out.println(res12); // >>> 3
                    return asyncCommands.hmget("bike:1:stats", "crashes", "owners");
                })
                        .thenAccept(System.out::println)
                        // >>> [KeyValue[crashes, 1], KeyValue[owners, 1]]
                        .toCompletableFuture();
    
                Mono<Void> incrByGetMget = reactiveCommands.hincrby("bike:1:stats", "rides", 1).doOnNext(result -> {
                    System.out.println(result); // >>> 1
                }).flatMap(v -> reactiveCommands.hincrby("bike:1:stats", "rides", 1)).doOnNext(result -> {
                    System.out.println(result); // >>> 2
                }).flatMap(v -> reactiveCommands.hincrby("bike:1:stats", "rides", 1)).doOnNext(result -> {
                    System.out.println(result); // >>> 3
                }).flatMap(v -> reactiveCommands.hincrby("bike:1:stats", "crashes", 1)).doOnNext(result -> {
                    System.out.println(result); // >>> 1
                }).flatMap(v -> reactiveCommands.hincrby("bike:1:stats", "owners", 1)).doOnNext(result -> {
                    System.out.println(result); // >>> 1
                }).then();
    
                incrByGetMget.block();
    
                Mono<String> getRides = reactiveCommands.hget("bike:1:stats", "rides").doOnNext(result -> {
                    System.out.println(result); // >>> 3
                });
    
                Mono<List<KeyValue<String, String>>> getCrashesOwners = reactiveCommands.hmget("bike:1:stats", "crashes", "owners")
                        .collectList().doOnNext(result -> {
                            System.out.println(result);
                            // >>> [KeyValue[crashes, 1], KeyValue[owners, 1]]
                        });
    
    	res8, err := rdb.HIncrBy(ctx, "bike:1:stats", "rides", 1).Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res8) // >>> 1
    
    	res9, err := rdb.HIncrBy(ctx, "bike:1:stats", "rides", 1).Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res9) // >>> 2
    
    	res10, err := rdb.HIncrBy(ctx, "bike:1:stats", "rides", 1).Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res10) // >>> 3
    
    	res11, err := rdb.HIncrBy(ctx, "bike:1:stats", "crashes", 1).Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res11) // >>> 1
    
    	res12, err := rdb.HIncrBy(ctx, "bike:1:stats", "owners", 1).Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res12) // >>> 1
    
    	res13, err := rdb.HGet(ctx, "bike:1:stats", "rides").Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res13) // >>> 3
    
    	res14, err := rdb.HMGet(ctx, "bike:1:stats", "crashes", "owners").Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res14) // >>> [1 1]
    
            var rides = db.HashIncrement("bike:1", "rides");
            Console.WriteLine($"Rides: {rides}");
            // Rides: 1
    
            rides = db.HashIncrement("bike:1", "rides");
            Console.WriteLine($"Rides: {rides}");
            // Rides: 2
    
            rides = db.HashIncrement("bike:1", "rides");
            Console.WriteLine($"Rides: {rides}");
            // Rides: 3
    
            var crashes = db.HashIncrement("bike:1", "crashes");
            Console.WriteLine($"Crashes: {crashes}");
            // Crashes: 1
    
            var owners = db.HashIncrement("bike:1", "owners");
            Console.WriteLine($"Owners: {owners}");
            // Owners: 1
    
            var stats = db.HashGet("bike:1", ["crashes", "owners"]);
            Console.WriteLine($"Bike stats: crashes={stats[0]}, owners={stats[1]}");
            // Bike stats: crashes=1, owners=1
    
            $res8 = $r->hincrby('bike:1:stats', 'rides', 1);
            echo $res8 . PHP_EOL;
            // >>> 1
    
            $res9 = $r->hincrby('bike:1:stats', 'rides', 1);
            echo $res9 . PHP_EOL;
            // >>> 2
    
            $res10 = $r->hincrby('bike:1:stats', 'rides', 1);
            echo $res10 . PHP_EOL;
            // >>> 3
    
            $res11 = $r->hincrby('bike:1:stats', 'crashes', 1);
            echo $res11 . PHP_EOL;
            // >>> 1
    
            $res12 = $r->hincrby('bike:1:stats', 'owners', 1);
            echo $res12 . PHP_EOL;
            // >>> 1
    
            $res13 = $r->hget('bike:1:stats', 'rides');
            echo $res13 . PHP_EOL;
            // >>> 3
    
            $res14 = $r->hmget('bike:1:stats', ['crashes', 'owners']);
            echo json_encode($res14) . PHP_EOL;
            // >>> ["1","1"]
    
    res8 = r.hincrby('bike:1:stats', 'rides', 1)
    puts res8 # 1
    
    res9 = r.hincrby('bike:1:stats', 'rides', 1)
    puts res9 # 2
    
    res10 = r.hincrby('bike:1:stats', 'rides', 1)
    puts res10 # 3
    
    res11 = r.hincrby('bike:1:stats', 'crashes', 1)
    puts res11 # 1
    
    res12 = r.hincrby('bike:1:stats', 'owners', 1)
    puts res12 # 1
    
    res13 = r.hget('bike:1:stats', 'rides')
    puts res13 # 3
    
    res14 = r.hmget('bike:1:stats', 'owners', 'crashes')
    puts res14.inspect # ["1", "1"]
    
            if let Ok(res) = r.hincr("bike:1:stats", "rides", 1) {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            }
    
            if let Ok(res) = r.hincr("bike:1:stats", "rides", 1) {
                let res: i32 = res;
                println!("{res}");    // >>> 2
            }
    
            if let Ok(res) = r.hincr("bike:1:stats", "rides", 1) {
                let res: i32 = res;
                println!("{res}");    // >>> 3
            }
    
            if let Ok(res) = r.hincr("bike:1:stats", "crashes", 1) {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            }
    
            if let Ok(res) = r.hincr("bike:1:stats", "owners", 1) {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            }
    
            match r.hget("bike:1:stats", "rides") {
                Ok(res) => {
                    let res: i32 = res;
                    println!("{res}");   // >>> 3
                },
                Err(e) => {
                    println!("Error getting bike:1:stats rides: {e}");
                    return;
                }
            };
    
            match r.hmget("bike:1:stats", &["crashes", "owners"]) {
                Ok(res) => {
                    let res: Vec<i32> = res;
                    println!("{res:?}");   // >>> [1, 1]
                },
                Err(e) => {
                    println!("Error getting bike:1:stats crashes and owners: {e}");
                    return;
                }
            };
    
            if let Ok(res) = r.hincr("bike:1:stats", "rides", 1).await {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            }
    
            if let Ok(res) = r.hincr("bike:1:stats", "rides", 1).await {
                let res: i32 = res;
                println!("{res}");    // >>> 2
            }
    
            if let Ok(res) = r.hincr("bike:1:stats", "rides", 1).await {
                let res: i32 = res;
                println!("{res}");    // >>> 3
            }
    
            if let Ok(res) = r.hincr("bike:1:stats", "crashes", 1).await {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            }
    
            if let Ok(res) = r.hincr("bike:1:stats", "owners", 1).await {
                let res: i32 = res;
                println!("{res}");    // >>> 1
            }
    
            match r.hget("bike:1:stats", "rides").await {
                Ok(res) => {
                    let res: i32 = res;
                    println!("{res}");   // >>> 3
                },
                Err(e) => {
                    println!("Error getting bike:1:stats rides: {e}");
                    return;
                }
            };
    
            match r.hmget("bike:1:stats", &["crashes", "owners"]).await {
                Ok(res) => {
                    let res: Vec<i32> = res;
                    println!("{res:?}");   // >>> [1, 1]
                },
                Err(e) => {
                    println!("Error getting bike:1:stats crashes and owners: {e}");
                    return;
                }
            };
    

Field expiration

Redis 7.4 introduced the ability to specify an expiration time or a time-to-live (TTL) value for individual hash fields. This capability is comparable to key expiration and includes a number of similar commands.

Use the following commands to set either an exact expiration time or a TTL value for specific fields:

  • HEXPIRE: set the remaining TTL in seconds.
  • HPEXPIRE: set the remaining TTL in milliseconds.
  • HEXPIREAT: set the expiration time to a timestamp1 specified in seconds.
  • HPEXPIREAT: set the expiration time to a timestamp specified in milliseconds.

Use the following commands to retrieve either the exact time when or the remaining TTL until specific fields will expire:

  • HEXPIRETIME: get the expiration time as a timestamp in seconds.
  • HPEXPIRETIME: get the expiration time as a timestamp in milliseconds.
  • HTTL: get the remaining TTL in seconds.
  • HPTTL: get the remaining TTL in milliseconds.

Use the following command to remove the expiration of specific fields:

Redis 8.0 introduced the following commands:

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

Common field expiration use cases

  1. Event Tracking: Use a hash key to store events from the last hour. Set each event's TTL to one hour. Use HLEN to count events from the past hour.

  2. Fraud Detection: Create a hash with hourly counters for events. Set each field's TTL to 48 hours. Query the hash to get the number of events per hour for the last 48 hours.

  3. Customer Session Management: Store customer data in hash keys. Create a new hash key for each session and add a session field to the customer’s hash key. Expire both the session key and the session field in the customer’s hash key automatically when the session expires.

  4. Active Session Tracking: Store all active sessions in a hash key. Set each session's TTL to expire automatically after inactivity. Use HLEN to count active sessions.

Field expiration examples

Hash field expiration is supported by the official client libraries. The examples below demonstrate the field expiration commands using a hash that stores sensor data with the following structure:

Field Value
air_quality 256
battery_level 89

Because the fields expire, each example recreates the sensor:sensor1 hash first so that it runs on its own.

Set a TTL of 60 seconds for two fields of a hash and then retrieve the remaining TTL for those fields:

Field expiration: Set a TTL in seconds on individual hash fields using HEXPIRE, then read the remaining TTL with HTTL
DEL sensor:sensor1 HSET sensor:sensor1 air_quality 256 battery_level 89 HEXPIRE sensor:sensor1 60 FIELDS 2 air_quality battery_level HTTL sensor:sensor1 FIELDS 2 air_quality battery_level
r.delete("sensor:sensor1")
r.hset("sensor:sensor1", mapping={"air_quality": 256, "battery_level": 89})

# Set a TTL of 60 seconds on two fields of the hash.
res18 = r.hexpire("sensor:sensor1", 60, "air_quality", "battery_level")
print(res18)
# >>> [1, 1]

# Retrieve the remaining TTL for those fields.
res19 = r.httl("sensor:sensor1", "air_quality", "battery_level")
print(res19)
# >>> [60, 60]
# (your actual values may be slightly lower)
await client.del('sensor:sensor1')
await client.hSet('sensor:sensor1', { 'air_quality': 256, 'battery_level': 89 })

// Set a TTL of 60 seconds on two fields of the hash.
const res18 = await client.hExpire('sensor:sensor1', ['air_quality', 'battery_level'], 60)
console.log(res18)  // [1, 1]

// Retrieve the remaining TTL for those fields.
const res19 = await client.hTTL('sensor:sensor1', ['air_quality', 'battery_level'])
console.log(res19)  // [60, 60] (or close to 60)
      jedis.del("sensor:sensor1");
      Map<String, String> sensor1 = new HashMap<>();
      sensor1.put("air_quality", "256");
      sensor1.put("battery_level", "89");
      jedis.hset("sensor:sensor1", sensor1);

      // Set a TTL of 60 seconds on two fields of the hash.
      List<Long> res15 = jedis.hexpire("sensor:sensor1", 60, "air_quality", "battery_level");
      System.out.println(res15); // [1, 1]

      // Retrieve the remaining TTL for those fields.
      List<Long> res16 = jedis.httl("sensor:sensor1", "air_quality", "battery_level");
      System.out.println(res16.size()); // 2
            Map<String, String> sensor1 = new HashMap<>();
            sensor1.put("air_quality", "256");
            sensor1.put("battery_level", "89");

            CompletableFuture<Void> hExpire = asyncCommands.del("sensor:sensor1")
                    .thenCompose(delRes -> asyncCommands.hset("sensor:sensor1", sensor1))
                    // Set a TTL of 60 seconds on two fields of the hash.
                    .thenCompose(hsetRes -> asyncCommands.hexpire("sensor:sensor1", 60, "air_quality", "battery_level"))
                    .thenCompose(res15 -> {
                        System.out.println(res15); // >>> [1, 1]
                        // Retrieve the remaining TTL for those fields.
                        return asyncCommands.httl("sensor:sensor1", "air_quality", "battery_level");
                    })
                    .thenAccept(res16 -> System.out.println(res16.size()))
                    // >>> 2
                    .toCompletableFuture();
            Map<String, String> sensor1 = new HashMap<>();
            sensor1.put("air_quality", "256");
            sensor1.put("battery_level", "89");

            // Set a TTL of 60 seconds on two fields of the hash.
            Mono<List<Long>> hExpire = reactiveCommands.del("sensor:sensor1")
                    .then(reactiveCommands.hset("sensor:sensor1", sensor1))
                    .then(reactiveCommands.hexpire("sensor:sensor1", 60, "air_quality", "battery_level").collectList())
                    .doOnNext(result -> {
                        System.out.println(result);
                        // >>> [1, 1]
                    });

            hExpire.block();

            // Retrieve the remaining TTL for those fields.
            Mono<List<Long>> hTtl = reactiveCommands.httl("sensor:sensor1", "air_quality", "battery_level")
                    .collectList().doOnNext(result -> {
                        System.out.println(result.size());
                        // >>> 2
                    });

            hTtl.block();
	rdb.Del(ctx, "sensor:sensor1")
	rdb.HSet(ctx, "sensor:sensor1", "air_quality", 256, "battery_level", 89)

	// Set a TTL of 60 seconds on two fields of the hash.
	res18, err := rdb.HExpire(ctx, "sensor:sensor1", 60*time.Second,
		"air_quality", "battery_level").Result()

	if err != nil {
		panic(err)
	}

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

	// Retrieve the remaining TTL for those fields (returns one value per field).
	res19, err := rdb.HTTL(ctx, "sensor:sensor1", "air_quality", "battery_level").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(len(res19)) // >>> 2
        db.KeyDelete("sensor:sensor1");
        db.HashSet("sensor:sensor1", [
            new("air_quality", 256),
            new("battery_level", 89)
        ]);

        // Set a TTL of 60 seconds on two fields of the hash.
        ExpireResult[] hexpireResult = db.HashFieldExpire(
            "sensor:sensor1",
            new RedisValue[] { "air_quality", "battery_level" },
            TimeSpan.FromSeconds(60)
        );
        Console.WriteLine(string.Join(", ", hexpireResult));
        // Success, Success

        // Retrieve the remaining TTL for those fields.
        long[] httlResult = db.HashFieldGetTimeToLive(
            "sensor:sensor1",
            new RedisValue[] { "air_quality", "battery_level" }
        );
        Console.WriteLine(httlResult.Length);
        // 2
        $r->del('sensor:sensor1');
        $r->hmset('sensor:sensor1', [
            'air_quality' => 256,
            'battery_level' => 89,
        ]);

        // Set a TTL of 60 seconds on two fields of the hash.
        $res15 = $r->hexpire('sensor:sensor1', 60, ['air_quality', 'battery_level']);
        echo json_encode($res15) . PHP_EOL;
        // >>> [1,1]

        // Retrieve the remaining TTL for those fields.
        $res16 = $r->httl('sensor:sensor1', ['air_quality', 'battery_level']);
        echo count($res16) . PHP_EOL;
        // >>> 2
        let _: () = r.del("sensor:sensor1").expect("Failed to del");
        let _: () = r.hset_multiple(
            "sensor:sensor1",
            &[("air_quality", "256"), ("battery_level", "89")],
        ).expect("Failed to hset");

        // Set a TTL of 60 seconds on two fields of the hash.
        match r.hexpire("sensor:sensor1", 60, redis::ExpireOption::NONE, &["air_quality", "battery_level"]) {
            Ok(res18) => {
                let res18: Vec<i64> = res18;
                println!("{:?}", res18);    // >>> [1, 1]
            },
            Err(e) => {
                println!("Error setting expiration: {e}");
                return;
            }
        }

        // Retrieve the remaining TTL for those fields.
        match r.httl("sensor:sensor1", &["air_quality", "battery_level"]) {
            Ok(res19) => {
                let res19: Vec<i64> = res19;
                println!("{}", res19.len());    // >>> 2
            },
            Err(e) => {
                println!("Error getting TTL: {e}");
                return;
            }
        }
        let _: () = r.del("sensor:sensor1").await.expect("Failed to del");
        let _: () = r.hset_multiple(
            "sensor:sensor1",
            &[("air_quality", "256"), ("battery_level", "89")],
        ).await.expect("Failed to hset");

        // Set a TTL of 60 seconds on two fields of the hash.
        match r.hexpire("sensor:sensor1", 60, redis::ExpireOption::NONE, &["air_quality", "battery_level"]).await {
            Ok(res18) => {
                let res18: Vec<i64> = res18;
                println!("{:?}", res18);    // >>> [1, 1]
            },
            Err(e) => {
                println!("Error setting expiration: {e}");
                return;
            }
        }

        // Retrieve the remaining TTL for those fields.
        match r.httl("sensor:sensor1", &["air_quality", "battery_level"]).await {
            Ok(res19) => {
                let res19: Vec<i64> = res19;
                println!("{}", res19.len());    // >>> 2
            },
            Err(e) => {
                println!("Error getting TTL: {e}");
                return;
            }
        }

Set a hash field's TTL in milliseconds and then retrieve the remaining TTL in milliseconds:

Field expiration: Set a TTL in milliseconds on a hash field using HPEXPIRE, then read the remaining TTL with HPTTL
DEL sensor:sensor1 HSET sensor:sensor1 air_quality 256 battery_level 89 HPEXPIRE sensor:sensor1 60000 FIELDS 1 air_quality HPTTL sensor:sensor1 FIELDS 1 air_quality
r.delete("sensor:sensor1")
r.hset("sensor:sensor1", mapping={"air_quality": 256, "battery_level": 89})

# Set the TTL of the 'air_quality' field in milliseconds.
res20 = r.hpexpire("sensor:sensor1", 60000, "air_quality")
print(res20)
# >>> [1]

# Retrieve the remaining TTL in milliseconds.
res21 = r.hpttl("sensor:sensor1", "air_quality")
print(res21)
# >>> [59994]
# (your actual value may vary)
await client.del('sensor:sensor1')
await client.hSet('sensor:sensor1', { 'air_quality': 256, 'battery_level': 89 })

// Set the TTL of the 'air_quality' field in milliseconds.
const res20 = await client.hpExpire('sensor:sensor1', ['air_quality'], 60000)
console.log(res20)  // [1]

// Retrieve the remaining TTL in milliseconds.
const res21 = await client.hpTTL('sensor:sensor1', ['air_quality'])
console.log(res21)  // [59994] (your actual value may vary)
      jedis.del("sensor:sensor1");
      jedis.hset("sensor:sensor1", sensor1);

      // Set the TTL of the 'air_quality' field in milliseconds.
      List<Long> res17 = jedis.hpexpire("sensor:sensor1", 60000, "air_quality");
      System.out.println(res17); // [1]

      // Retrieve the remaining TTL in milliseconds.
      List<Long> res18 = jedis.hpttl("sensor:sensor1", "air_quality");
      System.out.println(res18.size()); // 1
            CompletableFuture<Void> hpExpire = hExpire
                    .thenCompose(prev -> asyncCommands.del("sensor:sensor1"))
                    .thenCompose(delRes -> asyncCommands.hset("sensor:sensor1", sensor1))
                    // Set the TTL of the 'air_quality' field in milliseconds.
                    .thenCompose(hsetRes -> asyncCommands.hpexpire("sensor:sensor1", 60000, "air_quality"))
                    .thenCompose(res17 -> {
                        System.out.println(res17); // >>> [1]
                        // Retrieve the remaining TTL in milliseconds.
                        return asyncCommands.hpttl("sensor:sensor1", "air_quality");
                    })
                    .thenAccept(res18 -> System.out.println(res18.size()))
                    // >>> 1
                    .toCompletableFuture();
            // Set the TTL of the 'air_quality' field in milliseconds.
            Mono<List<Long>> hpExpire = reactiveCommands.del("sensor:sensor1")
                    .then(reactiveCommands.hset("sensor:sensor1", sensor1))
                    .then(reactiveCommands.hpexpire("sensor:sensor1", 60000, "air_quality").collectList())
                    .doOnNext(result -> {
                        System.out.println(result);
                        // >>> [1]
                    });

            hpExpire.block();

            // Retrieve the remaining TTL in milliseconds.
            Mono<List<Long>> hpTtl = reactiveCommands.hpttl("sensor:sensor1", "air_quality")
                    .collectList().doOnNext(result -> {
                        System.out.println(result.size());
                        // >>> 1
                    });

            hpTtl.block();
	rdb.Del(ctx, "sensor:sensor1")
	rdb.HSet(ctx, "sensor:sensor1", "air_quality", 256, "battery_level", 89)

	// Set the TTL of the 'air_quality' field in milliseconds.
	res20, err := rdb.HPExpire(ctx, "sensor:sensor1", 60000*time.Millisecond,
		"air_quality").Result()

	if err != nil {
		panic(err)
	}

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

	// Retrieve the remaining TTL in milliseconds (returns one value per field).
	res21, err := rdb.HPTTL(ctx, "sensor:sensor1", "air_quality").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(len(res21)) // >>> 1
        db.KeyDelete("sensor:sensor1");
        db.HashSet("sensor:sensor1", [
            new("air_quality", 256),
            new("battery_level", 89)
        ]);

        // Set the TTL of the 'air_quality' field, expressed in milliseconds.
        ExpireResult[] hpexpireResult = db.HashFieldExpire(
            "sensor:sensor1",
            new RedisValue[] { "air_quality" },
            TimeSpan.FromMilliseconds(60000)
        );
        Console.WriteLine(string.Join(", ", hpexpireResult));
        // Success

        // Retrieve the remaining TTL.
        long[] hpttlResult = db.HashFieldGetTimeToLive(
            "sensor:sensor1",
            new RedisValue[] { "air_quality" }
        );
        Console.WriteLine(hpttlResult.Length);
        // 1
        $r->del('sensor:sensor1');
        $r->hmset('sensor:sensor1', [
            'air_quality' => 256,
            'battery_level' => 89,
        ]);

        // Set the TTL of the 'air_quality' field in milliseconds.
        $res17 = $r->hpexpire('sensor:sensor1', 60000, ['air_quality']);
        echo json_encode($res17) . PHP_EOL;
        // >>> [1]

        // Retrieve the remaining TTL in milliseconds.
        $res18 = $r->hpttl('sensor:sensor1', ['air_quality']);
        echo count($res18) . PHP_EOL;
        // >>> 1
        let _: () = r.del("sensor:sensor1").expect("Failed to del");
        let _: () = r.hset_multiple(
            "sensor:sensor1",
            &[("air_quality", "256"), ("battery_level", "89")],
        ).expect("Failed to hset");

        // Set the TTL of the 'air_quality' field in milliseconds.
        match r.hpexpire("sensor:sensor1", 60000, redis::ExpireOption::NONE, &["air_quality"]) {
            Ok(res20) => {
                let res20: Vec<i64> = res20;
                println!("{:?}", res20);    // >>> [1]
            },
            Err(e) => {
                println!("Error setting expiration: {e}");
                return;
            }
        }

        // Retrieve the remaining TTL in milliseconds.
        match r.hpttl("sensor:sensor1", &["air_quality"]) {
            Ok(res21) => {
                let res21: Vec<i64> = res21;
                println!("{}", res21.len());    // >>> 1
            },
            Err(e) => {
                println!("Error getting PTTL: {e}");
                return;
            }
        }
        let _: () = r.del("sensor:sensor1").await.expect("Failed to del");
        let _: () = r.hset_multiple(
            "sensor:sensor1",
            &[("air_quality", "256"), ("battery_level", "89")],
        ).await.expect("Failed to hset");

        // Set the TTL of the 'air_quality' field in milliseconds.
        match r.hpexpire("sensor:sensor1", 60000, redis::ExpireOption::NONE, &["air_quality"]).await {
            Ok(res20) => {
                let res20: Vec<i64> = res20;
                println!("{:?}", res20);    // >>> [1]
            },
            Err(e) => {
                println!("Error setting expiration: {e}");
                return;
            }
        }

        // Retrieve the remaining TTL in milliseconds.
        match r.hpttl("sensor:sensor1", &["air_quality"]).await {
            Ok(res21) => {
                let res21: Vec<i64> = res21;
                println!("{}", res21.len());    // >>> 1
            },
            Err(e) => {
                println!("Error getting PTTL: {e}");
                return;
            }
        }

Set a hash field's expiration to a specific timestamp and then retrieve that expiration time (both as a Unix time in seconds):

Field expiration: Set an absolute expiration timestamp on a hash field using HEXPIREAT, then read it back with HEXPIRETIME
DEL sensor:sensor1 HSET sensor:sensor1 air_quality 256 battery_level 89 HEXPIREAT sensor:sensor1 1719855517 FIELDS 1 air_quality HEXPIRETIME sensor:sensor1 FIELDS 1 air_quality
r.delete("sensor:sensor1")
r.hset("sensor:sensor1", mapping={"air_quality": 256, "battery_level": 89})

# Set the expiration of 'air_quality' to a Unix time 24 hours from now.
res22 = r.hexpireat(
    "sensor:sensor1",
    int(time.time()) + 24 * 60 * 60,
    "air_quality",
)
print(res22)
# >>> [1]

# Retrieve the expiration time as a Unix timestamp in seconds.
res23 = r.hexpiretime("sensor:sensor1", "air_quality")
print(res23)
# >>> [1717668041]
# (your actual value will vary)
await client.del('sensor:sensor1')
await client.hSet('sensor:sensor1', { 'air_quality': 256, 'battery_level': 89 })

// Set the expiration of 'air_quality' to a Unix time 24 hours from now.
const expireAt = Math.floor(Date.now() / 1000) + 24 * 60 * 60
const res22 = await client.hExpireAt('sensor:sensor1', ['air_quality'], expireAt)
console.log(res22)  // [1]

// Retrieve the expiration time as a Unix timestamp in seconds.
const res23 = await client.hExpireTime('sensor:sensor1', ['air_quality'])
console.log(res23)  // [1717668041] (your actual value will vary)
      jedis.del("sensor:sensor1");
      jedis.hset("sensor:sensor1", sensor1);

      // Set the expiration of 'air_quality' to a Unix time 24 hours from now.
      long expireAt = System.currentTimeMillis() / 1000L + 24 * 60 * 60;
      List<Long> res19 = jedis.hexpireAt("sensor:sensor1", expireAt, "air_quality");
      System.out.println(res19); // [1]

      // Retrieve the expiration time as a Unix timestamp in seconds.
      List<Long> res20 = jedis.hexpireTime("sensor:sensor1", "air_quality");
      System.out.println(res20.size()); // 1
            long expireAtSeconds = System.currentTimeMillis() / 1000L + 24 * 60 * 60;
            CompletableFuture<Void> hExpireAt = hpExpire
                    .thenCompose(prev -> asyncCommands.del("sensor:sensor1"))
                    .thenCompose(delRes -> asyncCommands.hset("sensor:sensor1", sensor1))
                    // Set the expiration of 'air_quality' to a Unix time 24 hours from now.
                    .thenCompose(hsetRes -> asyncCommands.hexpireat("sensor:sensor1", expireAtSeconds, "air_quality"))
                    .thenCompose(res19 -> {
                        System.out.println(res19); // >>> [1]
                        // Retrieve the expiration time as a Unix timestamp in seconds.
                        return asyncCommands.hexpiretime("sensor:sensor1", "air_quality");
                    })
                    .thenAccept(res20 -> System.out.println(res20.size()))
                    // >>> 1
                    .toCompletableFuture();
            long expireAtSeconds = System.currentTimeMillis() / 1000L + 24 * 60 * 60;

            // Set the expiration of 'air_quality' to a Unix time 24 hours from now.
            Mono<List<Long>> hExpireAt = reactiveCommands.del("sensor:sensor1")
                    .then(reactiveCommands.hset("sensor:sensor1", sensor1))
                    .then(reactiveCommands.hexpireat("sensor:sensor1", expireAtSeconds, "air_quality").collectList())
                    .doOnNext(result -> {
                        System.out.println(result);
                        // >>> [1]
                    });

            hExpireAt.block();

            // Retrieve the expiration time as a Unix timestamp in seconds.
            Mono<List<Long>> hExpireTime = reactiveCommands.hexpiretime("sensor:sensor1", "air_quality")
                    .collectList().doOnNext(result -> {
                        System.out.println(result.size());
                        // >>> 1
                    });

            hExpireTime.block();
	rdb.Del(ctx, "sensor:sensor1")
	rdb.HSet(ctx, "sensor:sensor1", "air_quality", 256, "battery_level", 89)

	// Set the expiration of 'air_quality' to a time 24 hours from now.
	res22, err := rdb.HExpireAt(ctx, "sensor:sensor1", time.Now().Add(24*time.Hour),
		"air_quality").Result()

	if err != nil {
		panic(err)
	}

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

	// Retrieve the expiration time as a Unix timestamp (returns one value per field).
	res23, err := rdb.HExpireTime(ctx, "sensor:sensor1", "air_quality").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(len(res23)) // >>> 1
        db.KeyDelete("sensor:sensor1");
        db.HashSet("sensor:sensor1", [
            new("air_quality", 256),
            new("battery_level", 89)
        ]);

        // Set the expiration of 'air_quality' to a time 24 hours from now.
        ExpireResult[] hexpireAtResult = db.HashFieldExpire(
            "sensor:sensor1",
            new RedisValue[] { "air_quality" },
            DateTime.UtcNow.AddHours(24)
        );
        Console.WriteLine(string.Join(", ", hexpireAtResult));
        // Success

        // Retrieve the expiration time as a Unix timestamp.
        long[] hexpireTimeResult = db.HashFieldGetExpireDateTime(
            "sensor:sensor1",
            new RedisValue[] { "air_quality" }
        );
        Console.WriteLine(hexpireTimeResult.Length);
        // 1
        $r->del('sensor:sensor1');
        $r->hmset('sensor:sensor1', [
            'air_quality' => 256,
            'battery_level' => 89,
        ]);

        // Set the expiration of 'air_quality' to a Unix time 24 hours from now.
        $res19 = $r->hexpireat('sensor:sensor1', time() + 24 * 60 * 60, ['air_quality']);
        echo json_encode($res19) . PHP_EOL;
        // >>> [1]

        // Retrieve the expiration time as a Unix timestamp in seconds.
        $res20 = $r->hexpiretime('sensor:sensor1', ['air_quality']);
        echo count($res20) . PHP_EOL;
        // >>> 1
        let _: () = r.del("sensor:sensor1").expect("Failed to del");
        let _: () = r.hset_multiple(
            "sensor:sensor1",
            &[("air_quality", "256"), ("battery_level", "89")],
        ).expect("Failed to hset");

        // Set the expiration of 'air_quality' to a Unix time 24 hours from now.
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .expect("Time went backwards")
            .as_secs() as i64;

        match r.hexpire_at("sensor:sensor1", now + 24 * 60 * 60, redis::ExpireOption::NONE, &["air_quality"]) {
            Ok(res22) => {
                let res22: Vec<i64> = res22;
                println!("{:?}", res22);    // >>> [1]
            },
            Err(e) => {
                println!("Error setting expiration: {e}");
                return;
            }
        }

        // Retrieve the expiration time as a Unix timestamp in seconds.
        match r.hexpire_time("sensor:sensor1", &["air_quality"]) {
            Ok(res23) => {
                let res23: Vec<i64> = res23;
                println!("{}", res23.len());    // >>> 1
            },
            Err(e) => {
                println!("Error getting expiration time: {e}");
                return;
            }
        }
        let _: () = r.del("sensor:sensor1").await.expect("Failed to del");
        let _: () = r.hset_multiple(
            "sensor:sensor1",
            &[("air_quality", "256"), ("battery_level", "89")],
        ).await.expect("Failed to hset");

        // Set the expiration of 'air_quality' to a Unix time 24 hours from now.
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .expect("Time went backwards")
            .as_secs() as i64;

        match r.hexpire_at("sensor:sensor1", now + 24 * 60 * 60, redis::ExpireOption::NONE, &["air_quality"]).await {
            Ok(res22) => {
                let res22: Vec<i64> = res22;
                println!("{:?}", res22);    // >>> [1]
            },
            Err(e) => {
                println!("Error setting expiration: {e}");
                return;
            }
        }

        // Retrieve the expiration time as a Unix timestamp in seconds.
        match r.hexpire_time("sensor:sensor1", &["air_quality"]).await {
            Ok(res23) => {
                let res23: Vec<i64> = res23;
                println!("{}", res23.len());    // >>> 1
            },
            Err(e) => {
                println!("Error getting expiration time: {e}");
                return;
            }
        }

Performance

Most Redis hash commands are O(1).

A few commands, such as HKEYS, HVALS, HGETALL, and most of the expiration-related commands, are O(n), where n is the number of field-value pairs.

Limits

Every hash can store up to 4,294,967,295 (2^32 - 1) field-value pairs. In practice, your hashes are limited only by the overall memory on the VMs hosting your Redis deployment.

Learn more


  1. all timestamps are specified in seconds or milliseconds since the Unix epoch↩︎

RATE THIS PAGE
Back to top ↑