0
# Search and Indexing
1
2
Full-text search, indexing, and aggregation capabilities using RediSearch for complex query operations on Redis data. Provides powerful search features including full-text search, numeric filtering, geo-spatial queries, and advanced aggregation.
3
4
## Capabilities
5
6
### Index Management
7
8
Operations for creating, managing, and configuring search indexes.
9
10
```typescript { .api }
11
/**
12
* Create a search index with schema definition
13
* @param index - Name of the index
14
* @param schema - Index schema definition
15
* @param options - Optional index configuration
16
* @returns 'OK'
17
*/
18
function create(index: string, schema: RediSearchSchema, options?: FtCreateOptions): Promise<SimpleStringReply<'OK'>>;
19
20
/**
21
* Get information about a search index
22
* @param index - Name of the index
23
* @returns Array containing index information
24
*/
25
function info(index: string): Promise<ArrayReply>;
26
27
/**
28
* Drop a search index
29
* @param index - Name of the index
30
* @param options - Optional drop configuration
31
* @returns 'OK'
32
*/
33
function dropIndex(index: string, options?: FtDropIndexOptions): Promise<SimpleStringReply<'OK'>>;
34
35
/**
36
* Alter an existing index by adding new fields
37
* @param index - Name of the index
38
* @param schema - New fields to add to the schema
39
* @returns 'OK'
40
*/
41
function alter(index: string, schema: RediSearchSchema): Promise<SimpleStringReply<'OK'>>;
42
43
/**
44
* List all search indexes
45
* @returns Array of index names
46
*/
47
function _list(): Promise<ArrayReply<BlobStringReply>>;
48
49
interface RediSearchSchema {
50
[fieldName: string]: SchemaFieldDefinition;
51
}
52
53
interface SchemaFieldDefinition {
54
/** Field type */
55
type: SchemaFieldType;
56
/** Field is sortable */
57
SORTABLE?: boolean;
58
/** Field cannot be searched */
59
NOINDEX?: boolean;
60
/** Store original value for highlighting */
61
NOSTEM?: boolean;
62
/** Text field specific options */
63
WEIGHT?: number;
64
PHONETIC?: SchemaTextFieldPhonetic;
65
/** Numeric/geo field options */
66
SEPARATOR?: string;
67
/** Vector field options */
68
ALGORITHM?: SchemaVectorFieldAlgorithm;
69
DIM?: number;
70
DISTANCE_METRIC?: 'L2' | 'IP' | 'COSINE';
71
}
72
73
type SchemaFieldType = 'TEXT' | 'NUMERIC' | 'GEO' | 'TAG' | 'VECTOR';
74
type SchemaTextFieldPhonetic = 'dm:en' | 'dm:fr' | 'fm';
75
type SchemaVectorFieldAlgorithm = 'FLAT' | 'HNSW';
76
77
interface FtCreateOptions {
78
/** Key prefix for indexed documents */
79
PREFIX?: string | string[];
80
/** Custom key filter expression */
81
FILTER?: string;
82
/** Default language for text fields */
83
LANGUAGE?: RediSearchLanguage;
84
/** Default field for searches */
85
LANGUAGE_FIELD?: string;
86
/** Default score for documents */
87
SCORE?: number;
88
/** Field containing document score */
89
SCORE_FIELD?: string;
90
/** Field containing document payload */
91
PAYLOAD_FIELD?: string;
92
/** Maximum number of text records */
93
MAXTEXTFIELDS?: boolean;
94
/** Disable stemming */
95
NOSTEM?: boolean;
96
/** Disable stop words */
97
NOFREQS?: boolean;
98
/** Disable term offset vectors */
99
NOOFFSETS?: boolean;
100
/** Number of background indexing threads */
101
NOHL?: boolean;
102
/** Custom stop words */
103
STOPWORDS?: string[];
104
}
105
106
interface FtDropIndexOptions {
107
/** Also delete the documents */
108
DD?: boolean;
109
}
110
111
type RediSearchLanguage = 'arabic' | 'danish' | 'dutch' | 'english' | 'finnish' | 'french' | 'german' | 'hungarian' | 'italian' | 'norwegian' | 'portuguese' | 'romanian' | 'russian' | 'spanish' | 'swedish' | 'turkish' | 'chinese';
112
```
113
114
**Usage Examples:**
115
116
```typescript
117
import { createClient } from "redis";
118
119
const client = createClient();
120
await client.connect();
121
122
// Create a search index for products
123
await client.ft.create("products", {
124
name: { type: 'TEXT', SORTABLE: true },
125
description: { type: 'TEXT' },
126
price: { type: 'NUMERIC', SORTABLE: true },
127
category: { type: 'TAG', SORTABLE: true },
128
location: { type: 'GEO' },
129
tags: { type: 'TAG', SEPARATOR: ',' }
130
}, {
131
PREFIX: 'product:',
132
LANGUAGE: 'english'
133
});
134
135
// Get index information
136
const indexInfo = await client.ft.info("products");
137
console.log("Index info:", indexInfo);
138
139
// List all indexes
140
const indexes = await client.ft._list();
141
console.log("Available indexes:", indexes);
142
143
// Add new field to existing index
144
await client.ft.alter("products", {
145
brand: { type: 'TAG', SORTABLE: true }
146
});
147
148
// Drop index (keeping documents)
149
await client.ft.dropIndex("products");
150
151
// Drop index and delete documents
152
await client.ft.dropIndex("products", { DD: true });
153
```
154
155
### Search Operations
156
157
Core search functionality with query parsing and result formatting.
158
159
```typescript { .api }
160
/**
161
* Search the index with a query
162
* @param index - Name of the index
163
* @param query - Search query string
164
* @param options - Optional search parameters
165
* @returns Search results with documents and metadata
166
*/
167
function search(index: string, query: string, options?: FtSearchOptions): Promise<SearchReply>;
168
169
/**
170
* Search without returning document content
171
* @param index - Name of the index
172
* @param query - Search query string
173
* @param options - Optional search parameters
174
* @returns Search results with document IDs only
175
*/
176
function searchNoContent(index: string, query: string, options?: FtSearchOptions): Promise<SearchReply>;
177
178
/**
179
* Explain query execution plan
180
* @param index - Name of the index
181
* @param query - Search query string
182
* @param options - Optional query options
183
* @returns Query execution plan
184
*/
185
function explain(index: string, query: string, options?: FtExplainOptions): Promise<BlobStringReply>;
186
187
/**
188
* Profile search query performance
189
* @param index - Name of the index
190
* @param query - Search query string
191
* @param options - Optional search parameters
192
* @returns Profiling information with search results
193
*/
194
function profileSearch(index: string, query: string, options?: FtSearchOptions): Promise<ArrayReply>;
195
196
interface FtSearchOptions {
197
/** Return only document IDs */
198
NOCONTENT?: boolean;
199
/** Include term frequency information */
200
WITHSCORES?: boolean;
201
/** Include payload information */
202
WITHPAYLOADS?: boolean;
203
/** Sort by field */
204
SORTBY?: {
205
BY: string;
206
DIRECTION?: 'ASC' | 'DESC';
207
};
208
/** Limit results */
209
LIMIT?: {
210
from: number;
211
size: number;
212
};
213
/** Specific fields to return */
214
RETURN?: string[];
215
/** Highlight matching terms */
216
HIGHLIGHT?: {
217
FIELDS?: string[];
218
TAGS?: {
219
open: string;
220
close: string;
221
};
222
};
223
/** Summarize fields */
224
SUMMARIZE?: {
225
FIELDS?: string[];
226
FRAGS?: number;
227
LEN?: number;
228
SEPARATOR?: string;
229
};
230
/** Default language */
231
LANGUAGE?: RediSearchLanguage;
232
/** Expression filter */
233
FILTER?: string;
234
/** Geographic filter */
235
GEOFILTER?: {
236
field: string;
237
lon: number;
238
lat: number;
239
radius: number;
240
unit: 'm' | 'km' | 'mi' | 'ft';
241
};
242
/** Include term position information */
243
INKEYS?: string[];
244
/** Include tag values */
245
INFIELDS?: string[];
246
/** Return raw document values */
247
RETURN_RAW?: boolean;
248
/** Disable stemming */
249
NOSTEM?: boolean;
250
/** Custom scoring function */
251
SCORER?: string;
252
}
253
254
interface SearchReply {
255
/** Total number of results */
256
total: number;
257
/** Array of document results */
258
documents: SearchDocument[];
259
}
260
261
interface SearchDocument {
262
/** Document ID */
263
id: string;
264
/** Document score */
265
score?: number;
266
/** Document payload */
267
payload?: string;
268
/** Document fields */
269
value: Record<string, string>;
270
}
271
```
272
273
**Usage Examples:**
274
275
```typescript
276
// Add some sample data first
277
await client.hSet("product:1", {
278
name: "Smartphone",
279
description: "Latest Android smartphone with great camera",
280
price: "599",
281
category: "electronics",
282
tags: "mobile,android,camera"
283
});
284
285
await client.hSet("product:2", {
286
name: "Laptop",
287
description: "High-performance laptop for developers",
288
price: "1299",
289
category: "computers",
290
tags: "laptop,development,performance"
291
});
292
293
// Basic search
294
const results = await client.ft.search("products", "smartphone");
295
console.log(`Found ${results.total} results:`, results.documents);
296
297
// Search with options
298
const searchResults = await client.ft.search("products", "camera OR laptop", {
299
WITHSCORES: true,
300
SORTBY: { BY: "price", DIRECTION: "ASC" },
301
LIMIT: { from: 0, size: 10 },
302
HIGHLIGHT: {
303
FIELDS: ["name", "description"],
304
TAGS: { open: "<mark>", close: "</mark>" }
305
}
306
});
307
308
// Filtered search
309
const electronicsResults = await client.ft.search("products", "*", {
310
FILTER: "@category:{electronics}",
311
SORTBY: { BY: "price", DIRECTION: "DESC" }
312
});
313
314
// Price range search
315
const priceResults = await client.ft.search("products", "@price:[500 1000]");
316
317
// Geographic search (if location field exists)
318
const nearbyResults = await client.ft.search("products", "*", {
319
GEOFILTER: {
320
field: "location",
321
lon: -122.4194,
322
lat: 37.7749,
323
radius: 10,
324
unit: "km"
325
}
326
});
327
328
// Get search explanation
329
const explanation = await client.ft.explain("products", "smartphone camera");
330
console.log("Query plan:", explanation);
331
```
332
333
### Aggregation Operations
334
335
Advanced aggregation operations for complex data analysis and reporting.
336
337
```typescript { .api }
338
/**
339
* Perform aggregation query on search index
340
* @param index - Name of the index
341
* @param query - Search query string
342
* @param options - Aggregation pipeline steps
343
* @returns Aggregation results
344
*/
345
function aggregate(index: string, query: string, ...options: FtAggregateStep[]): Promise<ArrayReply>;
346
347
/**
348
* Perform aggregation with cursor for large result sets
349
* @param index - Name of the index
350
* @param query - Search query string
351
* @param options - Aggregation options with cursor configuration
352
* @returns Aggregation results with cursor
353
*/
354
function aggregateWithCursor(index: string, query: string, options?: FtAggregateWithCursorOptions): Promise<ArrayReply>;
355
356
/**
357
* Profile aggregation query performance
358
* @param index - Name of the index
359
* @param query - Search query string
360
* @param options - Aggregation pipeline steps
361
* @returns Profiling information with aggregation results
362
*/
363
function profileAggregate(index: string, query: string, ...options: FtAggregateStep[]): Promise<ArrayReply>;
364
365
type FtAggregateStep =
366
| { type: 'GROUPBY'; fields: string[]; reducers: FtAggregateGroupByReducer[] }
367
| { type: 'SORTBY'; fields: Array<{ field: string; direction?: 'ASC' | 'DESC' }> }
368
| { type: 'APPLY'; expression: string; as: string }
369
| { type: 'LIMIT'; offset: number; count: number }
370
| { type: 'FILTER'; expression: string };
371
372
type FtAggregateGroupByReducer =
373
| { type: 'COUNT'; as?: string }
374
| { type: 'COUNT_DISTINCT'; field: string; as?: string }
375
| { type: 'SUM'; field: string; as?: string }
376
| { type: 'MIN'; field: string; as?: string }
377
| { type: 'MAX'; field: string; as?: string }
378
| { type: 'AVG'; field: string; as?: string }
379
| { type: 'STDDEV'; field: string; as?: string }
380
| { type: 'TOLIST'; field: string; as?: string };
381
382
interface FtAggregateWithCursorOptions {
383
/** Cursor read size */
384
WITHCURSOR?: {
385
COUNT?: number;
386
MAXIDLE?: number;
387
};
388
/** Aggregation steps */
389
steps?: FtAggregateStep[];
390
}
391
```
392
393
**Usage Examples:**
394
395
```typescript
396
// Group by category and count
397
const categoryStats = await client.ft.aggregate("products", "*",
398
{
399
type: 'GROUPBY',
400
fields: ['@category'],
401
reducers: [
402
{ type: 'COUNT', as: 'count' },
403
{ type: 'AVG', field: '@price', as: 'avg_price' },
404
{ type: 'MIN', field: '@price', as: 'min_price' },
405
{ type: 'MAX', field: '@price', as: 'max_price' }
406
]
407
},
408
{
409
type: 'SORTBY',
410
fields: [{ field: '@count', direction: 'DESC' }]
411
}
412
);
413
414
// Price range analysis
415
const priceRanges = await client.ft.aggregate("products", "*",
416
{
417
type: 'APPLY',
418
expression: 'floor(@price/100)*100',
419
as: 'price_range'
420
},
421
{
422
type: 'GROUPBY',
423
fields: ['@price_range'],
424
reducers: [
425
{ type: 'COUNT', as: 'products_in_range' }
426
]
427
},
428
{
429
type: 'SORTBY',
430
fields: [{ field: '@price_range', direction: 'ASC' }]
431
}
432
);
433
434
// Complex aggregation with multiple steps
435
const complexAgg = await client.ft.aggregate("products", "electronics",
436
{
437
type: 'FILTER',
438
expression: '@price > 100'
439
},
440
{
441
type: 'APPLY',
442
expression: '@price * 0.1',
443
as: 'tax'
444
},
445
{
446
type: 'GROUPBY',
447
fields: ['@category'],
448
reducers: [
449
{ type: 'COUNT', as: 'count' },
450
{ type: 'SUM', field: '@price', as: 'total_price' },
451
{ type: 'SUM', field: '@tax', as: 'total_tax' }
452
]
453
},
454
{
455
type: 'LIMIT',
456
offset: 0,
457
count: 10
458
}
459
);
460
```
461
462
### Cursor Operations
463
464
Cursor-based operations for handling large result sets efficiently.
465
466
```typescript { .api }
467
/**
468
* Read from aggregation cursor
469
* @param index - Name of the index
470
* @param cursor - Cursor ID
471
* @param options - Read options
472
* @returns Next batch of results
473
*/
474
function cursorRead(index: string, cursor: number, options?: FtCursorReadOptions): Promise<ArrayReply>;
475
476
/**
477
* Delete aggregation cursor
478
* @param index - Name of the index
479
* @param cursor - Cursor ID
480
* @returns 'OK'
481
*/
482
function cursorDel(index: string, cursor: number): Promise<SimpleStringReply<'OK'>>;
483
484
interface FtCursorReadOptions {
485
/** Number of results to read */
486
COUNT?: number;
487
}
488
```
489
490
**Usage Examples:**
491
492
```typescript
493
// Create aggregation with cursor
494
const cursorResult = await client.ft.aggregateWithCursor("products", "*", {
495
WITHCURSOR: { COUNT: 100, MAXIDLE: 300000 },
496
steps: [
497
{
498
type: 'GROUPBY',
499
fields: ['@category'],
500
reducers: [{ type: 'COUNT', as: 'count' }]
501
}
502
]
503
});
504
505
// Extract cursor ID from result
506
const cursorId = cursorResult[cursorResult.length - 1];
507
508
// Read more results
509
const moreResults = await client.ft.cursorRead("products", cursorId, { COUNT: 50 });
510
511
// Clean up cursor
512
await client.ft.cursorDel("products", cursorId);
513
```
514
515
### Suggestion Operations
516
517
Auto-complete and suggestion functionality.
518
519
```typescript { .api }
520
/**
521
* Add suggestion to auto-complete dictionary
522
* @param key - Dictionary key
523
* @param string - Suggestion string
524
* @param score - Suggestion score
525
* @param options - Optional payload and increment behavior
526
* @returns Number of suggestions added
527
*/
528
function sugAdd(key: string, string: string, score: number, options?: FtSugAddOptions): Promise<NumberReply>;
529
530
/**
531
* Get suggestions from auto-complete dictionary
532
* @param key - Dictionary key
533
* @param prefix - Prefix to match
534
* @param options - Optional parameters for fuzzy matching and limits
535
* @returns Array of matching suggestions
536
*/
537
function sugGet(key: string, prefix: string, options?: FtSugGetOptions): Promise<ArrayReply<BlobStringReply>>;
538
539
/**
540
* Get suggestions with scores
541
* @param key - Dictionary key
542
* @param prefix - Prefix to match
543
* @param options - Optional parameters
544
* @returns Array of suggestions with scores
545
*/
546
function sugGetWithScores(key: string, prefix: string, options?: FtSugGetOptions): Promise<ArrayReply>;
547
548
/**
549
* Delete suggestion from dictionary
550
* @param key - Dictionary key
551
* @param string - Suggestion string to delete
552
* @returns 1 if deleted, 0 if not found
553
*/
554
function sugDel(key: string, string: string): Promise<BooleanReply>;
555
556
/**
557
* Get number of suggestions in dictionary
558
* @param key - Dictionary key
559
* @returns Number of suggestions
560
*/
561
function sugLen(key: string): Promise<NumberReply>;
562
563
interface FtSugAddOptions {
564
/** Increment score if suggestion exists */
565
INCR?: boolean;
566
/** Optional payload data */
567
PAYLOAD?: string;
568
}
569
570
interface FtSugGetOptions {
571
/** Enable fuzzy matching */
572
FUZZY?: boolean;
573
/** Maximum number of results */
574
MAX?: number;
575
/** Include scores in results */
576
WITHSCORES?: boolean;
577
/** Include payloads in results */
578
WITHPAYLOADS?: boolean;
579
}
580
```
581
582
**Usage Examples:**
583
584
```typescript
585
// Add suggestions to auto-complete
586
await client.ft.sugAdd("product_suggestions", "smartphone", 1.0);
587
await client.ft.sugAdd("product_suggestions", "smart tv", 0.8);
588
await client.ft.sugAdd("product_suggestions", "smart watch", 0.9, { PAYLOAD: "category:wearable" });
589
590
// Get suggestions
591
const suggestions = await client.ft.sugGet("product_suggestions", "smart", { MAX: 5 });
592
// ["smartphone", "smart watch", "smart tv"]
593
594
// Get suggestions with scores
595
const withScores = await client.ft.sugGetWithScores("product_suggestions", "smart", { MAX: 3 });
596
// ["smartphone", "1", "smart watch", "0.9", "smart tv", "0.8"]
597
598
// Fuzzy matching
599
const fuzzy = await client.ft.sugGet("product_suggestions", "smar", { FUZZY: true, MAX: 3 });
600
601
// Get suggestion count
602
const count = await client.ft.sugLen("product_suggestions"); // 3
603
604
// Delete suggestion
605
await client.ft.sugDel("product_suggestions", "smart tv");
606
```
607
608
### Dictionary and Synonym Management
609
610
Operations for managing dictionaries and synonyms.
611
612
```typescript { .api }
613
/**
614
* Add terms to dictionary
615
* @param dictionary - Dictionary name
616
* @param terms - Terms to add
617
* @returns Number of new terms added
618
*/
619
function dictAdd(dictionary: string, ...terms: string[]): Promise<NumberReply>;
620
621
/**
622
* Delete terms from dictionary
623
* @param dictionary - Dictionary name
624
* @param terms - Terms to delete
625
* @returns Number of terms deleted
626
*/
627
function dictDel(dictionary: string, ...terms: string[]): Promise<NumberReply>;
628
629
/**
630
* Dump all terms in dictionary
631
* @param dictionary - Dictionary name
632
* @returns Array of all terms in dictionary
633
*/
634
function dictDump(dictionary: string): Promise<ArrayReply<BlobStringReply>>;
635
636
/**
637
* Update synonym group
638
* @param index - Index name
639
* @param groupId - Synonym group ID
640
* @param terms - Terms in the synonym group
641
* @param options - Optional skip initial scan
642
* @returns 'OK'
643
*/
644
function synUpdate(index: string, groupId: string, terms: string[], options?: { SKIPINITIALSCAN?: boolean }): Promise<SimpleStringReply<'OK'>>;
645
646
/**
647
* Dump synonym groups
648
* @param index - Index name
649
* @returns Array of synonym group information
650
*/
651
function synDump(index: string): Promise<ArrayReply>;
652
```
653
654
**Usage Examples:**
655
656
```typescript
657
// Dictionary management
658
await client.ft.dictAdd("stopwords", "the", "a", "an", "and", "or", "but");
659
const stopwordCount = await client.ft.dictAdd("stopwords", "in", "on", "at"); // Returns count of new words
660
661
// View dictionary contents
662
const allStopwords = await client.ft.dictDump("stopwords");
663
664
// Remove words from dictionary
665
await client.ft.dictDel("stopwords", "but", "or");
666
667
// Synonym management
668
await client.ft.synUpdate("products", "smartphones", [
669
"smartphone", "mobile phone", "cell phone", "mobile device"
670
]);
671
672
await client.ft.synUpdate("products", "laptops", [
673
"laptop", "notebook", "portable computer"
674
]);
675
676
// View synonyms
677
const synonyms = await client.ft.synDump("products");
678
```
679
680
### Alias Management
681
682
Index alias operations for flexible index management.
683
684
```typescript { .api }
685
/**
686
* Add alias for an index
687
* @param alias - Alias name
688
* @param index - Target index name
689
* @returns 'OK'
690
*/
691
function aliasAdd(alias: string, index: string): Promise<SimpleStringReply<'OK'>>;
692
693
/**
694
* Delete an alias
695
* @param alias - Alias name to delete
696
* @returns 'OK'
697
*/
698
function aliasDel(alias: string): Promise<SimpleStringReply<'OK'>>;
699
700
/**
701
* Update alias to point to different index
702
* @param alias - Alias name
703
* @param index - New target index name
704
* @returns 'OK'
705
*/
706
function aliasUpdate(alias: string, index: string): Promise<SimpleStringReply<'OK'>>;
707
```
708
709
**Usage Examples:**
710
711
```typescript
712
// Create alias for current index
713
await client.ft.aliasAdd("current_products", "products_v1");
714
715
// Use alias in searches (same as using index name)
716
const results = await client.ft.search("current_products", "smartphone");
717
718
// Update alias to point to new index version
719
await client.ft.aliasUpdate("current_products", "products_v2");
720
721
// Delete alias when no longer needed
722
await client.ft.aliasDel("current_products");
723
```
724
725
## Search Query Syntax
726
727
RediSearch supports powerful query syntax for complex searches:
728
729
```typescript
730
// Query syntax examples:
731
"hello world" // Full-text search for both terms
732
"hello | world" // OR search
733
"hello -world" // Exclude term
734
"\"hello world\"" // Exact phrase
735
"hello*" // Prefix search
736
"%hello%" // Fuzzy search
737
"@title:hello" // Field-specific search
738
"@price:[100 200]" // Numeric range
739
"@location:[lat lon radius unit]" // Geographic filter
740
"@tags:{electronics|computers}" // Tag filter
741
"(@title:hello) (@price:[100 200])" // Complex query
742
```
743
744
## Constants and Enums
745
746
```typescript { .api }
747
const REDISEARCH_LANGUAGE = {
748
ARABIC: 'arabic',
749
DANISH: 'danish',
750
DUTCH: 'dutch',
751
ENGLISH: 'english',
752
FINNISH: 'finnish',
753
FRENCH: 'french',
754
GERMAN: 'german',
755
HUNGARIAN: 'hungarian',
756
ITALIAN: 'italian',
757
NORWEGIAN: 'norwegian',
758
PORTUGUESE: 'portuguese',
759
ROMANIAN: 'romanian',
760
RUSSIAN: 'russian',
761
SPANISH: 'spanish',
762
SWEDISH: 'swedish',
763
TURKISH: 'turkish',
764
CHINESE: 'chinese'
765
} as const;
766
767
const SCHEMA_FIELD_TYPE = {
768
TEXT: 'TEXT',
769
NUMERIC: 'NUMERIC',
770
GEO: 'GEO',
771
TAG: 'TAG',
772
VECTOR: 'VECTOR'
773
} as const;
774
775
const FT_AGGREGATE_GROUP_BY_REDUCERS = {
776
COUNT: 'COUNT',
777
COUNT_DISTINCT: 'COUNT_DISTINCT',
778
SUM: 'SUM',
779
MIN: 'MIN',
780
MAX: 'MAX',
781
AVG: 'AVG',
782
STDDEV: 'STDDEV',
783
TOLIST: 'TOLIST'
784
} as const;
785
```