# $range

`$range` groups documents into custom ranges.

Use it when bucket boundaries are defined by business logic (for example pricing tiers).

### Compatibility

| Field Type | Supported |
|------------|-----------|
| TEXT | No |
| U64/I64/F64 | Yes |
| DATE | Yes |
| BOOL | No |
| KEYWORD | No |
| FACET | No |

Field must be `FAST`.

### Arguments

| Argument | Type | Required | Description |
|----------|------|----------|-------------|
| `field` | `string` | Yes | Field to bucket on. |
| `ranges` | `Array<{ key?: string, from?: number, to?: number }>` | Yes | Non-empty array of range objects. |
| `keyed` | `boolean` | No | If `true`, returns buckets as an object. Default: `false`. |

`from` is inclusive. `to` is exclusive.

<Tabs>

<Tab title="TypeScript">
```ts
await index.aggregate({
  aggregations: {
    price_tiers: {
      $range: {
        field: "price",
        ranges: [{ to: 30 }, { from: 30, to: 60 }, { from: 60 }],
      },
    },
  },
});
```
</Tab>

<Tab title="Python">
```python
index.aggregate(
    aggregations={
        "price_tiers": {
            "$range": {
                "field": "price",
                "ranges": [{"to": 30}, {"from": 30, "to": 60}, {"from": 60}],
            }
        }
    }
)
```
</Tab>

<Tab title="Redis CLI">
```bash
SEARCH.AGGREGATE products '{}' '{"price_tiers": {"$range": {"field": "price", "ranges": [{"to": 30}, {"from": 30, "to": 60}, {"from": 60}]}}}'
```
</Tab>

</Tabs>

### Output

```json
{
  "price_tiers": {
    "buckets": [
      { "key": "*-30", "docCount": 3, "to": 30 },
      { "key": "30-60", "docCount": 3, "from": 30, "to": 60 },
      { "key": "60-*", "docCount": 3, "from": 60 }
    ]
  }
}
```

Bucket entries can include `fromAsString` / `toAsString` and nested sub-aggregation outputs.
