or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bloom-filters.mdclient-management.mdindex.mdjson-operations.mdredis-commands.mdsearch-indexing.mdtime-series.md

time-series.mddocs/

0

# Time Series

1

2

Time series data operations for storing and querying time-stamped data with aggregation rules and downsampling using RedisTimeSeries. Ideal for metrics, IoT data, financial data, and monitoring applications.

3

4

## Capabilities

5

6

### Series Management

7

8

Operations for creating and managing time series with metadata and configuration.

9

10

```typescript { .api }

11

/**

12

* Create a new time series

13

* @param key - Time series key

14

* @param options - Optional series configuration

15

* @returns 'OK'

16

*/

17

function create(key: RedisArgument, options?: TsCreateOptions): Promise<SimpleStringReply<'OK'>>;

18

19

/**

20

* Alter time series configuration

21

* @param key - Time series key

22

* @param options - Configuration changes

23

* @returns 'OK'

24

*/

25

function alter(key: RedisArgument, options: TsAlterOptions): Promise<SimpleStringReply<'OK'>>;

26

27

/**

28

* Get time series information and statistics

29

* @param key - Time series key

30

* @returns Array containing series metadata and stats

31

*/

32

function info(key: RedisArgument): Promise<ArrayReply>;

33

34

/**

35

* Get detailed debug information about time series

36

* @param key - Time series key

37

* @returns Array containing debug information

38

*/

39

function infoDebug(key: RedisArgument): Promise<ArrayReply>;

40

41

/**

42

* Query time series index by labels

43

* @param filters - Label filter expressions

44

* @returns Array of matching time series keys

45

*/

46

function queryIndex(...filters: string[]): Promise<ArrayReply<BlobStringReply>>;

47

48

interface TsCreateOptions {

49

/** Data retention period in milliseconds */

50

RETENTION?: number;

51

/** Encoding algorithm */

52

ENCODING?: TimeSeriesEncoding;

53

/** Chunk size in bytes */

54

CHUNK_SIZE?: number;

55

/** Duplicate sample policy */

56

DUPLICATE_POLICY?: TimeSeriesDuplicatePolicies;

57

/** Labels for the series */

58

LABELS?: Record<string, string>;

59

}

60

61

interface TsAlterOptions {

62

/** Data retention period in milliseconds */

63

RETENTION?: number;

64

/** Chunk size in bytes */

65

CHUNK_SIZE?: number;

66

/** Duplicate sample policy */

67

DUPLICATE_POLICY?: TimeSeriesDuplicatePolicies;

68

/** Labels for the series */

69

LABELS?: Record<string, string>;

70

}

71

72

type TimeSeriesEncoding = 'COMPRESSED' | 'UNCOMPRESSED';

73

type TimeSeriesDuplicatePolicies = 'BLOCK' | 'FIRST' | 'LAST' | 'MIN' | 'MAX' | 'SUM';

74

```

75

76

**Usage Examples:**

77

78

```typescript

79

import { createClient } from "redis";

80

81

const client = createClient();

82

await client.connect();

83

84

// Create time series with configuration

85

await client.ts.create("temperature:sensor1", {

86

RETENTION: 86400000, // 24 hours in milliseconds

87

LABELS: {

88

sensor: "temperature",

89

location: "room1",

90

building: "office"

91

},

92

DUPLICATE_POLICY: 'LAST',

93

ENCODING: 'COMPRESSED'

94

});

95

96

// Create multiple related series

97

await client.ts.create("humidity:sensor1", {

98

RETENTION: 86400000,

99

LABELS: {

100

sensor: "humidity",

101

location: "room1",

102

building: "office"

103

}

104

});

105

106

// Get series information

107

const info = await client.ts.info("temperature:sensor1");

108

console.log("Series info:", info);

109

110

// Query by labels

111

const temperatureSensors = await client.ts.queryIndex("sensor=temperature");

112

const room1Sensors = await client.ts.queryIndex("location=room1");

113

const allOfficeSensors = await client.ts.queryIndex("building=office");

114

115

// Alter existing series

116

await client.ts.alter("temperature:sensor1", {

117

RETENTION: 172800000, // Extend to 48 hours

118

LABELS: {

119

sensor: "temperature",

120

location: "room1",

121

building: "office",

122

calibrated: "2023-01-01"

123

}

124

});

125

```

126

127

### Data Operations

128

129

Core operations for adding, retrieving, and manipulating time series data points.

130

131

```typescript { .api }

132

/**

133

* Add sample to time series

134

* @param key - Time series key

135

* @param timestamp - Unix timestamp in milliseconds, or '*' for current time

136

* @param value - Numeric value

137

* @param options - Optional add parameters

138

* @returns The timestamp of the added sample

139

*/

140

function add(key: RedisArgument, timestamp: number | '*', value: number, options?: TsAddOptions): Promise<NumberReply>;

141

142

/**

143

* Add multiple samples to multiple time series

144

* @param samples - Array of sample specifications

145

* @returns Array of timestamps for added samples

146

*/

147

function mAdd(...samples: TsSample[]): Promise<ArrayReply<NumberReply>>;

148

149

/**

150

* Increment time series value

151

* @param key - Time series key

152

* @param value - Value to increment by

153

* @param options - Optional increment parameters

154

* @returns The timestamp of the incremented sample

155

*/

156

function incrBy(key: RedisArgument, value: number, options?: TsIncrByOptions): Promise<NumberReply>;

157

158

/**

159

* Decrement time series value

160

* @param key - Time series key

161

* @param value - Value to decrement by

162

* @param options - Optional decrement parameters

163

* @returns The timestamp of the decremented sample

164

*/

165

function decrBy(key: RedisArgument, value: number, options?: TsDecrByOptions): Promise<NumberReply>;

166

167

/**

168

* Delete samples in time range

169

* @param key - Time series key

170

* @param fromTimestamp - Start timestamp (inclusive)

171

* @param toTimestamp - End timestamp (inclusive)

172

* @returns Number of samples deleted

173

*/

174

function del(key: RedisArgument, fromTimestamp: number, toTimestamp: number): Promise<NumberReply>;

175

176

interface TsAddOptions {

177

/** Data retention period in milliseconds */

178

RETENTION?: number;

179

/** Encoding algorithm */

180

ENCODING?: TimeSeriesEncoding;

181

/** Chunk size in bytes */

182

CHUNK_SIZE?: number;

183

/** Only add if key doesn't exist */

184

ON_DUPLICATE?: TimeSeriesDuplicatePolicies;

185

/** Labels for new series */

186

LABELS?: Record<string, string>;

187

}

188

189

interface TsIncrByOptions extends TsAddOptions {

190

/** Custom timestamp (default: current time) */

191

TIMESTAMP?: number;

192

}

193

194

interface TsDecrByOptions extends TsAddOptions {

195

/** Custom timestamp (default: current time) */

196

TIMESTAMP?: number;

197

}

198

199

interface TsSample {

200

key: RedisArgument;

201

timestamp: number | '*';

202

value: number;

203

}

204

```

205

206

**Usage Examples:**

207

208

```typescript

209

// Add single sample with current timestamp

210

const timestamp1 = await client.ts.add("temperature:sensor1", "*", 23.5);

211

212

// Add sample with specific timestamp

213

const timestamp2 = await client.ts.add("temperature:sensor1", Date.now(), 24.1);

214

215

// Add sample with options (auto-create series)

216

const timestamp3 = await client.ts.add("pressure:sensor2", "*", 1013.25, {

217

LABELS: {

218

sensor: "pressure",

219

location: "room1",

220

unit: "hPa"

221

},

222

RETENTION: 86400000,

223

ON_DUPLICATE: 'LAST'

224

});

225

226

// Add multiple samples at once

227

await client.ts.mAdd(

228

{ key: "temperature:sensor1", timestamp: "*", value: 22.8 },

229

{ key: "humidity:sensor1", timestamp: "*", value: 65.2 },

230

{ key: "pressure:sensor1", timestamp: "*", value: 1012.8 }

231

);

232

233

// Increment counter-style metrics

234

const counterTs = await client.ts.incrBy("requests:total", 1, {

235

LABELS: { metric: "requests", service: "api" }

236

});

237

238

// Decrement with custom timestamp

239

await client.ts.decrBy("available:slots", 5, {

240

TIMESTAMP: Date.now() - 1000 // 1 second ago

241

});

242

243

// Delete old data

244

const deletedCount = await client.ts.del(

245

"temperature:sensor1",

246

Date.now() - 7 * 24 * 60 * 60 * 1000, // 7 days ago

247

Date.now() - 24 * 60 * 60 * 1000 // 1 day ago

248

);

249

```

250

251

### Data Retrieval

252

253

Operations for querying time series data with various filtering and aggregation options.

254

255

```typescript { .api }

256

/**

257

* Get latest sample from time series

258

* @param key - Time series key

259

* @returns Array containing timestamp and value, or null if empty

260

*/

261

function get(key: RedisArgument): Promise<ArrayReply | null>;

262

263

/**

264

* Get latest samples from multiple time series

265

* @param keys - Array of time series keys

266

* @param options - Optional filter parameters

267

* @returns Array of time series data with latest samples

268

*/

269

function mGet(keys: RedisArgument[], options?: TsMGetOptions): Promise<ArrayReply>;

270

271

/**

272

* Get latest samples from multiple time series with labels

273

* @param keys - Array of time series keys

274

* @param options - Optional filter parameters

275

* @returns Array of time series data with labels and latest samples

276

*/

277

function mGetWithLabels(keys: RedisArgument[], options?: TsMGetOptions): Promise<ArrayReply>;

278

279

/**

280

* Get samples from time range

281

* @param key - Time series key

282

* @param fromTimestamp - Start timestamp (inclusive)

283

* @param toTimestamp - End timestamp (inclusive)

284

* @param options - Optional range parameters

285

* @returns Array of timestamp-value pairs

286

*/

287

function range(key: RedisArgument, fromTimestamp: number, toTimestamp: number, options?: TsRangeOptions): Promise<ArrayReply>;

288

289

/**

290

* Get samples from time range in reverse order

291

* @param key - Time series key

292

* @param fromTimestamp - Start timestamp (inclusive)

293

* @param toTimestamp - End timestamp (inclusive)

294

* @param options - Optional range parameters

295

* @returns Array of timestamp-value pairs in reverse order

296

*/

297

function revRange(key: RedisArgument, fromTimestamp: number, toTimestamp: number, options?: TsRangeOptions): Promise<ArrayReply>;

298

299

interface TsMGetOptions {

300

/** Label filters */

301

FILTER?: string[];

302

/** Include series labels in response */

303

WITHLABELS?: boolean;

304

/** Include only selected labels */

305

SELECTED_LABELS?: string[];

306

}

307

308

interface TsRangeOptions {

309

/** Filter by minimum value */

310

FILTER_BY_TS?: number[];

311

/** Filter by value range */

312

FILTER_BY_VALUE?: [min: number, max: number];

313

/** Limit number of samples */

314

COUNT?: number;

315

/** Align timestamps to bucket */

316

ALIGN?: number;

317

/** Aggregation configuration */

318

AGGREGATION?: {

319

type: TimeSeriesAggregationType;

320

bucketDuration: number;

321

BUCKETTIMESTAMP?: TimeSeriesBucketTimestamp;

322

EMPTY?: boolean;

323

};

324

}

325

326

type TimeSeriesAggregationType = 'AVG' | 'SUM' | 'MIN' | 'MAX' | 'RANGE' | 'COUNT' | 'STD.P' | 'STD.S' | 'VAR.P' | 'VAR.S' | 'FIRST' | 'LAST';

327

type TimeSeriesBucketTimestamp = '-' | 'low' | 'high' | 'mid';

328

```

329

330

**Usage Examples:**

331

332

```typescript

333

// Get latest sample

334

const latest = await client.ts.get("temperature:sensor1");

335

if (latest) {

336

const [timestamp, value] = latest;

337

console.log(`Latest: ${value}°C at ${new Date(timestamp)}`);

338

}

339

340

// Get latest from multiple series

341

const latestMultiple = await client.ts.mGet([

342

"temperature:sensor1",

343

"humidity:sensor1",

344

"pressure:sensor1"

345

]);

346

347

// Get latest with labels

348

const latestWithLabels = await client.ts.mGetWithLabels([

349

"temperature:sensor1"

350

], {

351

WITHLABELS: true

352

});

353

354

// Get range of data

355

const hourlyData = await client.ts.range(

356

"temperature:sensor1",

357

Date.now() - 60 * 60 * 1000, // 1 hour ago

358

Date.now() // now

359

);

360

361

// Get aggregated data (5-minute averages)

362

const averageData = await client.ts.range(

363

"temperature:sensor1",

364

Date.now() - 24 * 60 * 60 * 1000, // 24 hours ago

365

Date.now(),

366

{

367

AGGREGATION: {

368

type: 'AVG',

369

bucketDuration: 5 * 60 * 1000, // 5 minutes

370

BUCKETTIMESTAMP: 'mid'

371

}

372

}

373

);

374

375

// Get filtered range

376

const filteredData = await client.ts.range(

377

"temperature:sensor1",

378

Date.now() - 60 * 60 * 1000,

379

Date.now(),

380

{

381

FILTER_BY_VALUE: [20, 30], // Only values between 20-30

382

COUNT: 100 // Limit to 100 samples

383

}

384

);

385

386

// Get reverse chronological data

387

const recentData = await client.ts.revRange(

388

"temperature:sensor1",

389

Date.now() - 60 * 60 * 1000,

390

Date.now(),

391

{

392

COUNT: 10 // Last 10 samples

393

}

394

);

395

```

396

397

### Multi-Series Queries

398

399

Advanced querying operations across multiple time series with filtering and aggregation.

400

401

```typescript { .api }

402

/**

403

* Query multiple time series by labels in time range

404

* @param fromTimestamp - Start timestamp

405

* @param toTimestamp - End timestamp

406

* @param filters - Label filter expressions

407

* @param options - Optional query parameters

408

* @returns Array of time series data

409

*/

410

function mRange(fromTimestamp: number, toTimestamp: number, filters: string[], options?: TsMRangeOptions): Promise<ArrayReply>;

411

412

/**

413

* Query multiple time series with labels in time range

414

* @param fromTimestamp - Start timestamp

415

* @param toTimestamp - End timestamp

416

* @param filters - Label filter expressions

417

* @param options - Optional query parameters

418

* @returns Array of time series data with labels

419

*/

420

function mRangeWithLabels(fromTimestamp: number, toTimestamp: number, filters: string[], options?: TsMRangeOptions): Promise<ArrayReply>;

421

422

/**

423

* Query multiple time series in reverse order

424

* @param fromTimestamp - Start timestamp

425

* @param toTimestamp - End timestamp

426

* @param filters - Label filter expressions

427

* @param options - Optional query parameters

428

* @returns Array of time series data in reverse order

429

*/

430

function mRevRange(fromTimestamp: number, toTimestamp: number, filters: string[], options?: TsMRangeOptions): Promise<ArrayReply>;

431

432

/**

433

* Query with grouping and reduction

434

* @param fromTimestamp - Start timestamp

435

* @param toTimestamp - End timestamp

436

* @param filters - Label filter expressions

437

* @param groupBy - Labels to group by

438

* @param reducer - Reduction function

439

* @param options - Optional query parameters

440

* @returns Array of grouped and reduced time series data

441

*/

442

function mRangeGroupBy(

443

fromTimestamp: number,

444

toTimestamp: number,

445

filters: string[],

446

groupBy: string,

447

reducer: TimeSeriesReducer,

448

options?: TsMRangeOptions

449

): Promise<ArrayReply>;

450

451

interface TsMRangeOptions {

452

/** Include series labels in response */

453

WITHLABELS?: boolean;

454

/** Include only selected labels */

455

SELECTED_LABELS?: string[];

456

/** Limit number of samples per series */

457

COUNT?: number;

458

/** Aggregation configuration */

459

AGGREGATION?: {

460

type: TimeSeriesAggregationType;

461

bucketDuration: number;

462

BUCKETTIMESTAMP?: TimeSeriesBucketTimestamp;

463

EMPTY?: boolean;

464

};

465

/** Filter by value range */

466

FILTER_BY_VALUE?: [min: number, max: number];

467

/** Filter by timestamp array */

468

FILTER_BY_TS?: number[];

469

/** Align timestamps */

470

ALIGN?: number;

471

}

472

473

type TimeSeriesReducer = 'SUM' | 'MIN' | 'MAX' | 'AVG' | 'STD.P' | 'STD.S' | 'VAR.P' | 'VAR.S' | 'COUNT';

474

```

475

476

**Usage Examples:**

477

478

```typescript

479

// Query all temperature sensors for last hour

480

const allTemperatures = await client.ts.mRange(

481

Date.now() - 60 * 60 * 1000, // 1 hour ago

482

Date.now(),

483

["sensor=temperature"]

484

);

485

486

// Query with labels and aggregation

487

const avgTemperatures = await client.ts.mRangeWithLabels(

488

Date.now() - 24 * 60 * 60 * 1000, // 24 hours ago

489

Date.now(),

490

["sensor=temperature", "building=office"],

491

{

492

WITHLABELS: true,

493

AGGREGATION: {

494

type: 'AVG',

495

bucketDuration: 60 * 60 * 1000, // 1 hour buckets

496

BUCKETTIMESTAMP: 'mid'

497

}

498

}

499

);

500

501

// Group by location and average

502

const locationAverages = await client.ts.mRangeGroupBy(

503

Date.now() - 60 * 60 * 1000,

504

Date.now(),

505

["sensor=temperature"],

506

"location",

507

"AVG",

508

{

509

AGGREGATION: {

510

type: 'AVG',

511

bucketDuration: 5 * 60 * 1000 // 5 minute buckets

512

}

513

}

514

);

515

516

// Complex multi-series query

517

const complexQuery = await client.ts.mRange(

518

Date.now() - 2 * 60 * 60 * 1000, // 2 hours ago

519

Date.now(),

520

["building=office", "location!=server_room"],

521

{

522

COUNT: 100,

523

FILTER_BY_VALUE: [18, 35], // Reasonable temperature range

524

AGGREGATION: {

525

type: 'MAX',

526

bucketDuration: 10 * 60 * 1000, // 10 minute max values

527

EMPTY: true // Include empty buckets

528

}

529

}

530

);

531

```

532

533

### Aggregation Rules

534

535

Operations for creating and managing downsampling and aggregation rules.

536

537

```typescript { .api }

538

/**

539

* Create aggregation rule between time series

540

* @param sourceKey - Source time series key

541

* @param destKey - Destination time series key

542

* @param aggregation - Aggregation configuration

543

* @param options - Optional rule parameters

544

* @returns 'OK'

545

*/

546

function createRule(

547

sourceKey: RedisArgument,

548

destKey: RedisArgument,

549

aggregation: TsAggregation,

550

options?: TsCreateRuleOptions

551

): Promise<SimpleStringReply<'OK'>>;

552

553

/**

554

* Delete aggregation rule

555

* @param sourceKey - Source time series key

556

* @param destKey - Destination time series key

557

* @returns 'OK'

558

*/

559

function deleteRule(sourceKey: RedisArgument, destKey: RedisArgument): Promise<SimpleStringReply<'OK'>>;

560

561

interface TsAggregation {

562

/** Aggregation type */

563

type: TimeSeriesAggregationType;

564

/** Time bucket duration in milliseconds */

565

bucketDuration: number;

566

/** Bucket timestamp alignment */

567

BUCKETTIMESTAMP?: TimeSeriesBucketTimestamp;

568

}

569

570

interface TsCreateRuleOptions {

571

/** Alignment timestamp */

572

alignTimestamp?: number;

573

}

574

```

575

576

**Usage Examples:**

577

578

```typescript

579

// Create destination series for aggregated data

580

await client.ts.create("temperature:sensor1:hourly", {

581

RETENTION: 30 * 24 * 60 * 60 * 1000, // 30 days

582

LABELS: {

583

sensor: "temperature",

584

location: "room1",

585

resolution: "hourly"

586

}

587

});

588

589

await client.ts.create("temperature:sensor1:daily", {

590

RETENTION: 365 * 24 * 60 * 60 * 1000, // 1 year

591

LABELS: {

592

sensor: "temperature",

593

location: "room1",

594

resolution: "daily"

595

}

596

});

597

598

// Create aggregation rules

599

await client.ts.createRule(

600

"temperature:sensor1", // Source: raw data

601

"temperature:sensor1:hourly", // Destination: hourly averages

602

{

603

type: 'AVG',

604

bucketDuration: 60 * 60 * 1000, // 1 hour

605

BUCKETTIMESTAMP: 'mid'

606

}

607

);

608

609

await client.ts.createRule(

610

"temperature:sensor1:hourly", // Source: hourly data

611

"temperature:sensor1:daily", // Destination: daily averages

612

{

613

type: 'AVG',

614

bucketDuration: 24 * 60 * 60 * 1000, // 1 day

615

BUCKETTIMESTAMP: 'low'

616

}

617

);

618

619

// Create multiple aggregation rules for different statistics

620

const sensors = ["temperature:sensor1", "humidity:sensor1"];

621

const aggregations = [

622

{ suffix: "min", type: 'MIN' as const },

623

{ suffix: "max", type: 'MAX' as const },

624

{ suffix: "avg", type: 'AVG' as const }

625

];

626

627

for (const sensor of sensors) {

628

for (const agg of aggregations) {

629

const destKey = `${sensor}:hourly:${agg.suffix}`;

630

631

// Create destination series

632

await client.ts.create(destKey, {

633

RETENTION: 7 * 24 * 60 * 60 * 1000, // 7 days

634

LABELS: {

635

source: sensor,

636

aggregation: agg.type,

637

resolution: "hourly"

638

}

639

});

640

641

// Create rule

642

await client.ts.createRule(sensor, destKey, {

643

type: agg.type,

644

bucketDuration: 60 * 60 * 1000 // 1 hour

645

});

646

}

647

}

648

649

// Delete rule when no longer needed

650

await client.ts.deleteRule("temperature:sensor1", "temperature:sensor1:hourly");

651

```

652

653

## Label Filtering Syntax

654

655

Time series queries support powerful label filtering:

656

657

```typescript

658

// Label filter examples:

659

"sensor=temperature" // Exact match

660

"location!=server_room" // Not equal

661

"building=(office|warehouse)" // Multiple values

662

"priority=(high|critical)" // OR condition

663

"sensor=temperature location=room1" // AND condition (space-separated)

664

"sensor!=pressure" // Exclude sensor type

665

```

666

667

**Usage Examples:**

668

669

```typescript

670

// Query with various label filters

671

const officeTemperatures = await client.ts.queryIndex("sensor=temperature", "building=office");

672

673

const nonServerMetrics = await client.ts.queryIndex("location!=server_room");

674

675

const criticalMetrics = await client.ts.queryIndex("priority=(high|critical)");

676

677

const roomSensors = await client.ts.queryIndex("location=(room1|room2|room3)", "sensor=temperature");

678

```

679

680

## Constants and Enums

681

682

```typescript { .api }

683

const TIME_SERIES_ENCODING = {

684

COMPRESSED: 'COMPRESSED',

685

UNCOMPRESSED: 'UNCOMPRESSED'

686

} as const;

687

688

const TIME_SERIES_DUPLICATE_POLICIES = {

689

BLOCK: 'BLOCK',

690

FIRST: 'FIRST',

691

LAST: 'LAST',

692

MIN: 'MIN',

693

MAX: 'MAX',

694

SUM: 'SUM'

695

} as const;

696

697

const TIME_SERIES_AGGREGATION_TYPE = {

698

AVG: 'AVG',

699

SUM: 'SUM',

700

MIN: 'MIN',

701

MAX: 'MAX',

702

RANGE: 'RANGE',

703

COUNT: 'COUNT',

704

STD_P: 'STD.P',

705

STD_S: 'STD.S',

706

VAR_P: 'VAR.P',

707

VAR_S: 'VAR.S',

708

FIRST: 'FIRST',

709

LAST: 'LAST'

710

} as const;

711

712

const TIME_SERIES_BUCKET_TIMESTAMP = {

713

LOW: 'low',

714

HIGH: 'high',

715

MID: 'mid'

716

} as const;

717

718

const TIME_SERIES_REDUCERS = {

719

SUM: 'SUM',

720

MIN: 'MIN',

721

MAX: 'MAX',

722

AVG: 'AVG',

723

STD_P: 'STD.P',

724

STD_S: 'STD.S',

725

VAR_P: 'VAR.P',

726

VAR_S: 'VAR.S',

727

COUNT: 'COUNT'

728

} as const;

729

```