# HSETEX

> Set hash fields with expiration support.

The `HSETEX` command sets the specified fields with their values and optionally sets their expiration time or TTL. It supports conditional operations to control when fields should be set.

## Arguments

<ParamField body="key" type="string" required>
  The key of the hash.
</ParamField>

<ParamField body="options" type="object">
  Options for conditional setting and expiration.

  <Expandable title="properties">
    <ParamField body="conditional" type="'FNX' | 'fnx' | 'FXX' | 'fxx'">
      Conditional setting options (case-insensitive):
      - `FNX`: Only set fields if the hash does not exist
      - `FXX`: Only set fields if the hash already exists
    </ParamField>

    <ParamField body="expiration" type="object">
      Expiration options for the hash.

      <Expandable title="expiration">
        <ParamField body="ex" type="number">
          Set expiration time in seconds.
        </ParamField>

        <ParamField body="px" type="number">
          Set expiration time in milliseconds.
        </ParamField>

        <ParamField body="exat" type="number">
          Set expiration as Unix timestamp in seconds.
        </ParamField>

        <ParamField body="pxat" type="number">
          Set expiration as Unix timestamp in milliseconds.
        </ParamField>

        <ParamField body="keepttl" type="true">
          Retain the existing time to live (TTL) associated with the hash key when setting fields. If the hash has an expiration, it will be preserved. Set to `true` to enable.
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="fields" type="{ [fieldName]: TValue }" required>
  An object of fields and their values to set.
</ParamField>

## Response

<ResponseField type="number" required>
  The number of fields that were set. Returns 0 if conditions are not met (e.g., `conditional: "FNX"` but hash exists, or `conditional: "FXX"` but hash doesn't exist).
</ResponseField>

<RequestExample>
```ts Basic Example
// Set fields with 1 hour expiration
await redis.hsetex("user:123", { expiration: { ex: 3600 } }, { 
  name: "John", 
  email: "john@example.com" 
});
```

```ts With FNX (only if hash doesn't exist)
// Set fields only if the hash doesn't exist
const result = await redis.hsetex(
  "user:456", 
  { conditional: "FNX" }, 
  { name: "Jane", age: "25" }
);
console.log(result); // 2 (if hash didn't exist)

// Try again - will return 0 since hash now exists
const result2 = await redis.hsetex(
  "user:456", 
  { conditional: "FNX" }, 
  { email: "jane@example.com" }
);
console.log(result2); // 0
```

```ts With FXX (only if hash exists)
// First create the hash
await redis.hset("session:abc", { token: "xyz" });

// Update only if hash exists
const result = await redis.hsetex(
  "session:abc", 
  { conditional: "FXX" }, 
  { user: "john" }
);
console.log(result); // 1 (hash exists, field added)

// Try on non-existent hash
const result2 = await redis.hsetex(
  "session:nonexistent", 
  { conditional: "FXX" }, 
  { user: "jane" }
);
console.log(result2); // 0 (hash doesn't exist)
```

```ts With PX (milliseconds)
// Set fields with 30 second expiration
await redis.hsetex("cache:data", { expiration: { px: 30000 } }, { 
  value: "cached data",
  timestamp: Date.now().toString()
});
```

```ts With EXAT (Unix timestamp in seconds)
// Set expiration to specific timestamp
const futureTime = Math.floor(Date.now() / 1000) + 7200; // 2 hours from now
await redis.hsetex("temp:data", { expiration: { exat: futureTime } }, { 
  info: "temporary information" 
});
```

```ts With PXAT (Unix timestamp in milliseconds)
// Set expiration to specific timestamp in milliseconds
const futureTime = Date.now() + 300000; // 5 minutes from now
await redis.hsetex("session:xyz", { expiration: { pxat: futureTime } }, { 
  token: "abc123",
  user: "john"
});
```

```ts Combined: Conditional + Expiration
// Set fields only if hash doesn't exist, with 1 hour expiration
await redis.hsetex(
  "user:789", 
  { 
    conditional: "FNX", 
    expiration: { ex: 3600 } 
  }, 
  { 
    name: "Alice",
    email: "alice@example.com",
    created: Date.now().toString()
  }
);
```

```ts With KEEPTTL
// First set fields with expiration
await redis.hsetex("cache:data", { expiration: { ex: 300 } }, { 
  value: "cached" 
});

// Later update fields while retaining the existing TTL
const result = await redis.hsetex(
  "cache:data", 
  { expiration: { keepttl: true } }, 
  { updated: "yes" }
);
console.log(result); // 1

// Verify TTL is still 300 seconds (or less if time passed)
const ttl = await redis.ttl("cache:data");
console.log(ttl); // Should be > 0 and <= 300 (TTL was retained)
```

```ts Without Options
// Just set fields without expiration or conditions
await redis.hsetex("data:simple", undefined, { 
  field1: "value1", 
  field2: "value2" 
});
```
</RequestExample>

## Use Cases

- **Session Management**: Create sessions with automatic expiration
- **Cache with TTL**: Store cached data that expires automatically
- **Temporary Data**: Create temporary records with built-in cleanup
- **Rate Limiting**: Store rate limit counters with automatic reset
- **Conditional Updates**: Ensure data consistency with FNX/FXX options
