...

Source file src/github.com/redis/go-redis/v9/doctests/timeseries_tut_test.go

Documentation: github.com/redis/go-redis/v9/doctests

     1  // EXAMPLE: time_series_tutorial
     2  // HIDE_START
     3  package example_commands_test
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"maps"
     9  	"math"
    10  	"slices"
    11  	"sort"
    12  
    13  	"github.com/redis/go-redis/v9"
    14  )
    15  
    16  // HIDE_END
    17  
    18  func ExampleClient_timeseries_create() {
    19  	ctx := context.Background()
    20  
    21  	rdb := redis.NewClient(&redis.Options{
    22  		Addr:     "localhost:6379",
    23  		Password: "", // no password set
    24  		DB:       0,  // use default DB
    25  	})
    26  
    27  	// REMOVE_START
    28  	// make sure we are working with fresh database
    29  	rdb.FlushDB(ctx)
    30  	rdb.Del(ctx, "thermometer:1", "thermometer:2", "thermometer:3")
    31  	// REMOVE_END
    32  
    33  	// STEP_START create
    34  	res1, err := rdb.TSCreate(ctx, "thermometer:1").Result()
    35  	if err != nil {
    36  		panic(err)
    37  	}
    38  
    39  	fmt.Println(res1) // >>> OK
    40  
    41  	res2, err := rdb.Type(ctx, "thermometer:1").Result()
    42  	if err != nil {
    43  		panic(err)
    44  	}
    45  
    46  	fmt.Println(res2) // >>> TSDB-TYPE
    47  
    48  	res3, err := rdb.TSInfo(ctx, "thermometer:1").Result()
    49  	if err != nil {
    50  		panic(err)
    51  	}
    52  
    53  	fmt.Println(res3["totalSamples"]) // >>> 0
    54  	// STEP_END
    55  
    56  	// STEP_START create_retention
    57  	res4, err := rdb.TSAddWithArgs(
    58  		ctx,
    59  		"thermometer:2",
    60  		1,
    61  		10.8,
    62  		&redis.TSOptions{
    63  			Retention: 100,
    64  		},
    65  	).Result()
    66  	if err != nil {
    67  		panic(err)
    68  	}
    69  
    70  	fmt.Println(res4) // >>> 1
    71  
    72  	res5, err := rdb.TSInfo(ctx, "thermometer:2").Result()
    73  	if err != nil {
    74  		panic(err)
    75  	}
    76  
    77  	fmt.Println(res5["retentionTime"]) // >>> 100
    78  	// STEP_END
    79  
    80  	// STEP_START create_labels
    81  	res6, err := rdb.TSAddWithArgs(
    82  		ctx,
    83  		"thermometer:3",
    84  		1,
    85  		10.4,
    86  		&redis.TSOptions{
    87  			Labels: map[string]string{
    88  				"location": "UK",
    89  				"type":     "Mercury",
    90  			},
    91  		},
    92  	).Result()
    93  	if err != nil {
    94  		panic(err)
    95  	}
    96  
    97  	fmt.Println(res6) // >>> 1
    98  
    99  	res7, err := rdb.TSInfo(ctx, "thermometer:3").Result()
   100  	if err != nil {
   101  		panic(err)
   102  	}
   103  
   104  	fmt.Println(res7["labels"])
   105  	// >>> map[location:UK type:Mercury]
   106  	// STEP_END
   107  
   108  	// Output:
   109  	// OK
   110  	// TSDB-TYPE
   111  	// 0
   112  	// 1
   113  	// 100
   114  	// 1
   115  	// map[location:UK type:Mercury]
   116  }
   117  
   118  func ExampleClient_timeseries_add() {
   119  	ctx := context.Background()
   120  
   121  	rdb := redis.NewClient(&redis.Options{
   122  		Addr:     "localhost:6379",
   123  		Password: "", // no password set
   124  		DB:       0,  // use default DB
   125  	})
   126  
   127  	// REMOVE_START
   128  	// make sure we are working with fresh database
   129  	rdb.FlushDB(ctx)
   130  	rdb.Del(ctx, "thermometer:1", "thermometer:2")
   131  	rdb.TSCreate(ctx, "thermometer:1")
   132  	rdb.TSCreate(ctx, "thermometer:2")
   133  	// REMOVE_END
   134  
   135  	// STEP_START madd
   136  	res1, err := rdb.TSMAdd(ctx, [][]interface{}{
   137  		{"thermometer:1", 1, 9.2},
   138  		{"thermometer:1", 2, 9.9},
   139  		{"thermometer:2", 2, 10.3},
   140  	}).Result()
   141  	if err != nil {
   142  		panic(err)
   143  	}
   144  
   145  	fmt.Println(res1) // >>> [1 2 2]
   146  	// STEP_END
   147  
   148  	// STEP_START get
   149  	// The last recorded temperature for thermometer:2
   150  	// was 10.3 at time 2.
   151  	res2, err := rdb.TSGet(ctx, "thermometer:2").Result()
   152  	if err != nil {
   153  		panic(err)
   154  	}
   155  
   156  	fmt.Println(res2)
   157  	// >>> {2 10.3}
   158  	// STEP_END
   159  
   160  	// Output:
   161  	// [1 2 2]
   162  	// {2 10.3}
   163  }
   164  
   165  func ExampleClient_timeseries_range() {
   166  	ctx := context.Background()
   167  
   168  	rdb := redis.NewClient(&redis.Options{
   169  		Addr:     "localhost:6379",
   170  		Password: "", // no password set
   171  		DB:       0,  // use default DB
   172  	})
   173  
   174  	// REMOVE_START
   175  	// make sure we are working with fresh database
   176  	rdb.FlushDB(ctx)
   177  	rdb.Del(ctx, "rg:1")
   178  	// REMOVE_END
   179  
   180  	// STEP_START range
   181  	// Add 5 data points to a time series named "rg:1".
   182  	res1, err := rdb.TSCreate(ctx, "rg:1").Result()
   183  	if err != nil {
   184  		panic(err)
   185  	}
   186  
   187  	fmt.Println(res1) // >>> OK
   188  
   189  	res2, err := rdb.TSMAdd(ctx, [][]interface{}{
   190  		{"rg:1", 0, 18},
   191  		{"rg:1", 1, 14},
   192  		{"rg:1", 2, 22},
   193  		{"rg:1", 3, 18},
   194  		{"rg:1", 4, 24},
   195  	}).Result()
   196  	if err != nil {
   197  		panic(err)
   198  	}
   199  
   200  	fmt.Println(res2) // >>> [0 1 2 3 4]
   201  
   202  	// Retrieve all the data points in ascending order.
   203  	// Note: use 0 and `math.MaxInt64` instead of - and +
   204  	// to denote the minimum and maximum possible timestamps.
   205  	res3, err := rdb.TSRange(ctx, "rg:1", 0, math.MaxInt64).Result()
   206  	if err != nil {
   207  		panic(err)
   208  	}
   209  
   210  	fmt.Println(res3)
   211  	// >>> [{0 18} {1 14} {2 22} {3 18} {4 24}]
   212  
   213  	// Retrieve data points up to time 1 (inclusive).
   214  	res4, err := rdb.TSRange(ctx, "rg:1", 0, 1).Result()
   215  	if err != nil {
   216  		panic(err)
   217  	}
   218  
   219  	fmt.Println(res4)
   220  	// >>> [{0 18} {1 14}]
   221  
   222  	// Retrieve data points from time 3 onwards.
   223  	res5, err := rdb.TSRange(ctx, "rg:1", 3, math.MaxInt64).Result()
   224  	if err != nil {
   225  		panic(err)
   226  	}
   227  
   228  	fmt.Println(res5)
   229  	// >>> [{3 18} {4 24}]
   230  
   231  	// Retrieve all the data points in descending order.
   232  	res6, err := rdb.TSRevRange(ctx, "rg:1", 0, math.MaxInt64).Result()
   233  	if err != nil {
   234  		panic(err)
   235  	}
   236  
   237  	fmt.Println(res6)
   238  	// >>> [{4 24} {3 18} {2 22} {1 14} {0 18}]
   239  
   240  	// Retrieve data points up to time 1 (inclusive), but return them
   241  	// in descending order.
   242  	res7, err := rdb.TSRevRange(ctx, "rg:1", 0, 1).Result()
   243  	if err != nil {
   244  		panic(err)
   245  	}
   246  
   247  	fmt.Println(res7)
   248  	// >>> [{1 14} {0 18}]
   249  	// STEP_END
   250  
   251  	// STEP_START range_filter
   252  	res8, err := rdb.TSRangeWithArgs(
   253  		ctx,
   254  		"rg:1",
   255  		0,
   256  		math.MaxInt64,
   257  		&redis.TSRangeOptions{
   258  			FilterByTS: []int{0, 2, 4},
   259  		},
   260  	).Result()
   261  	if err != nil {
   262  		panic(err)
   263  	}
   264  
   265  	fmt.Println(res8) // >>> [{0 18} {2 22} {4 24}]
   266  
   267  	res9, err := rdb.TSRevRangeWithArgs(
   268  		ctx,
   269  		"rg:1",
   270  		0,
   271  		math.MaxInt64,
   272  		&redis.TSRevRangeOptions{
   273  			FilterByTS:    []int{0, 2, 4},
   274  			FilterByValue: []int{20, 25},
   275  		},
   276  	).Result()
   277  	if err != nil {
   278  		panic(err)
   279  	}
   280  
   281  	fmt.Println(res9) // >>> [{4 24} {2 22}]
   282  
   283  	res10, err := rdb.TSRevRangeWithArgs(
   284  		ctx,
   285  		"rg:1",
   286  		0,
   287  		math.MaxInt64,
   288  		&redis.TSRevRangeOptions{
   289  			FilterByTS:    []int{0, 2, 4},
   290  			FilterByValue: []int{22, 22},
   291  		},
   292  	).Result()
   293  	if err != nil {
   294  		panic(err)
   295  	}
   296  
   297  	fmt.Println(res10) // >>> [{2 22}]
   298  	// STEP_END
   299  
   300  	// Output:
   301  	// OK
   302  	// [0 1 2 3 4]
   303  	// [{0 18} {1 14} {2 22} {3 18} {4 24}]
   304  	// [{0 18} {1 14}]
   305  	// [{3 18} {4 24}]
   306  	// [{4 24} {3 18} {2 22} {1 14} {0 18}]
   307  	// [{1 14} {0 18}]
   308  	// [{0 18} {2 22} {4 24}]
   309  	// [{4 24} {2 22}]
   310  	// [{2 22}]
   311  }
   312  
   313  func ExampleClient_timeseries_query_multi() {
   314  	ctx := context.Background()
   315  
   316  	rdb := redis.NewClient(&redis.Options{
   317  		Addr:     "localhost:6379",
   318  		Password: "", // no password set
   319  		DB:       0,  // use default DB
   320  	})
   321  
   322  	// REMOVE_START
   323  	// make sure we are working with fresh database
   324  	rdb.FlushDB(ctx)
   325  	rdb.Del(ctx, "rg:2", "rg:3", "rg:4")
   326  	// REMOVE_END
   327  
   328  	// STEP_START query_multi
   329  	// Create three new "rg:" time series (two in the US
   330  	// and one in the UK, with different units) and add some
   331  	// data points.
   332  	res20, err := rdb.TSCreateWithArgs(ctx, "rg:2", &redis.TSOptions{
   333  		Labels: map[string]string{"location": "us", "unit": "cm"},
   334  	}).Result()
   335  	if err != nil {
   336  		panic(err)
   337  	}
   338  
   339  	fmt.Println(res20) // >>> OK
   340  
   341  	res21, err := rdb.TSCreateWithArgs(ctx, "rg:3", &redis.TSOptions{
   342  		Labels: map[string]string{"location": "us", "unit": "in"},
   343  	}).Result()
   344  	if err != nil {
   345  		panic(err)
   346  	}
   347  
   348  	fmt.Println(res21) // >>> OK
   349  
   350  	res22, err := rdb.TSCreateWithArgs(ctx, "rg:4", &redis.TSOptions{
   351  		Labels: map[string]string{"location": "uk", "unit": "mm"},
   352  	}).Result()
   353  	if err != nil {
   354  		panic(err)
   355  	}
   356  
   357  	fmt.Println(res22) // >>> OK
   358  
   359  	res23, err := rdb.TSMAdd(ctx, [][]interface{}{
   360  		{"rg:2", 0, 1.8},
   361  		{"rg:3", 0, 0.9},
   362  		{"rg:4", 0, 25},
   363  	}).Result()
   364  	if err != nil {
   365  		panic(err)
   366  	}
   367  
   368  	fmt.Println(res23) // >>> [0 0 0]
   369  
   370  	res24, err := rdb.TSMAdd(ctx, [][]interface{}{
   371  		{"rg:2", 1, 2.1},
   372  		{"rg:3", 1, 0.77},
   373  		{"rg:4", 1, 18},
   374  	}).Result()
   375  	if err != nil {
   376  		panic(err)
   377  	}
   378  
   379  	fmt.Println(res24) // >>> [1 1 1]
   380  
   381  	res25, err := rdb.TSMAdd(ctx, [][]interface{}{
   382  		{"rg:2", 2, 2.3},
   383  		{"rg:3", 2, 1.1},
   384  		{"rg:4", 2, 21},
   385  	}).Result()
   386  	if err != nil {
   387  		panic(err)
   388  	}
   389  
   390  	fmt.Println(res25) // >>> [2 2 2]
   391  
   392  	res26, err := rdb.TSMAdd(ctx, [][]interface{}{
   393  		{"rg:2", 3, 1.9},
   394  		{"rg:3", 3, 0.81},
   395  		{"rg:4", 3, 19},
   396  	}).Result()
   397  	if err != nil {
   398  		panic(err)
   399  	}
   400  
   401  	fmt.Println(res26) // >>> [3 3 3]
   402  
   403  	res27, err := rdb.TSMAdd(ctx, [][]interface{}{
   404  		{"rg:2", 4, 1.78},
   405  		{"rg:3", 4, 0.74},
   406  		{"rg:4", 4, 23},
   407  	}).Result()
   408  	if err != nil {
   409  		panic(err)
   410  	}
   411  
   412  	fmt.Println(res27) // >>> [4 4 4]
   413  
   414  	// Retrieve the last data point from each US time series.
   415  	res28, err := rdb.TSMGet(ctx, []string{"location=us"}).Result()
   416  	if err != nil {
   417  		panic(err)
   418  	}
   419  
   420  	res28Keys := slices.Collect(maps.Keys(res28))
   421  	sort.Strings(res28Keys)
   422  
   423  	for _, k := range res28Keys {
   424  		labels := res28[k][0].(map[interface{}]interface{})
   425  
   426  		labelKeys := make([]string, 0, len(labels))
   427  
   428  		for lk := range labels {
   429  			labelKeys = append(labelKeys, lk.(string))
   430  		}
   431  
   432  		sort.Strings(labelKeys)
   433  
   434  		fmt.Printf("%v:\n", k)
   435  
   436  		for _, lk := range labelKeys {
   437  			fmt.Printf("  %v: %v\n", lk, labels[lk])
   438  		}
   439  
   440  		fmt.Printf("  %v\n", res28[k][1])
   441  	}
   442  	// >>> rg:2:
   443  	// >>>   {4 1.78}
   444  	// >>> rg:3:
   445  	// >>>   {4 0.74}
   446  
   447  	// Retrieve the same data points, but include the `unit`
   448  	// label in the results.
   449  	res29, err := rdb.TSMGetWithArgs(
   450  		ctx,
   451  		[]string{"location=us"},
   452  		&redis.TSMGetOptions{
   453  			SelectedLabels: []interface{}{"unit"},
   454  		},
   455  	).Result()
   456  	if err != nil {
   457  		panic(err)
   458  	}
   459  
   460  	res29Keys := slices.Collect(maps.Keys(res29))
   461  	sort.Strings(res29Keys)
   462  
   463  	for _, k := range res29Keys {
   464  		labels := res29[k][0].(map[interface{}]interface{})
   465  
   466  		labelKeys := make([]string, 0, len(labels))
   467  
   468  		for lk := range labels {
   469  			labelKeys = append(labelKeys, lk.(string))
   470  		}
   471  
   472  		sort.Strings(labelKeys)
   473  
   474  		fmt.Printf("%v:\n", k)
   475  
   476  		for _, lk := range labelKeys {
   477  			fmt.Printf("  %v: %v\n", lk, labels[lk])
   478  		}
   479  
   480  		fmt.Printf("  %v\n", res29[k][1])
   481  	}
   482  
   483  	// >>> rg:2:
   484  	// >>>   unit: cm
   485  	// >>>   [4 1.78]
   486  	// >>> rg:3:
   487  	// >>>   unit: in
   488  	// >>>   [4 0.74]
   489  
   490  	// Retrieve data points up to time 2 (inclusive) from all
   491  	// time series that use millimeters as the unit. Include all
   492  	// labels in the results.
   493  	// Note that the `aggregators` field is empty if you don't
   494  	// specify any aggregators.
   495  	res30, err := rdb.TSMRangeWithArgs(
   496  		ctx,
   497  		0,
   498  		2,
   499  		[]string{"unit=mm"},
   500  		&redis.TSMRangeOptions{
   501  			WithLabels: true,
   502  		},
   503  	).Result()
   504  	if err != nil {
   505  		panic(err)
   506  	}
   507  
   508  	res30Keys := slices.Collect(maps.Keys(res30))
   509  	sort.Strings(res30Keys)
   510  
   511  	for _, k := range res30Keys {
   512  		labels := res30[k][0].(map[interface{}]interface{})
   513  		labelKeys := make([]string, 0, len(labels))
   514  
   515  		for lk := range labels {
   516  			labelKeys = append(labelKeys, lk.(string))
   517  		}
   518  
   519  		sort.Strings(labelKeys)
   520  
   521  		fmt.Printf("%v:\n", k)
   522  
   523  		for _, lk := range labelKeys {
   524  			fmt.Printf("  %v: %v\n", lk, labels[lk])
   525  		}
   526  
   527  		fmt.Printf("  Aggregators: %v\n", res30[k][1])
   528  		fmt.Printf("  %v\n", res30[k][2])
   529  	}
   530  	// >>> rg:4:
   531  	// >>>   location: uk
   532  	// >>>   unit: mm
   533  	// >>>   Aggregators: map[aggregators:[]]
   534  	// >>>   [{0 25} {1 18} {2 21}]
   535  
   536  	// Retrieve data points from time 1 to time 3 (inclusive) from
   537  	// all time series that use centimeters or millimeters as the unit,
   538  	// but only return the `location` label. Return the results
   539  	// in descending order of timestamp.
   540  	res31, err := rdb.TSMRevRangeWithArgs(
   541  		ctx,
   542  		1,
   543  		3,
   544  		[]string{"unit=(cm,mm)"},
   545  		&redis.TSMRevRangeOptions{
   546  			SelectedLabels: []interface{}{"location"},
   547  		},
   548  	).Result()
   549  	if err != nil {
   550  		panic(err)
   551  	}
   552  
   553  	res31Keys := slices.Collect(maps.Keys(res31))
   554  	sort.Strings(res31Keys)
   555  
   556  	for _, k := range res31Keys {
   557  		labels := res31[k][0].(map[interface{}]interface{})
   558  		labelKeys := make([]string, 0, len(labels))
   559  
   560  		for lk := range labels {
   561  			labelKeys = append(labelKeys, lk.(string))
   562  		}
   563  
   564  		sort.Strings(labelKeys)
   565  
   566  		fmt.Printf("%v:\n", k)
   567  
   568  		for _, lk := range labelKeys {
   569  			fmt.Printf("  %v: %v\n", lk, labels[lk])
   570  		}
   571  
   572  		fmt.Printf("  Aggregators: %v\n", res31[k][1])
   573  		fmt.Printf("  %v\n", res31[k][2])
   574  	}
   575  	// >>> rg:2:
   576  	// >>>   location: us
   577  	// >>>   Aggregators: map[aggregators:[]]
   578  	// >>>   [{3 1.9} {2 2.3} {1 2.1}]
   579  	// >>> rg:4:
   580  	// >>>   location: uk
   581  	// >>>   Aggregators: map[aggregators:[]]
   582  	// >>>   [{3 19} {2 21} {1 18}]
   583  	// STEP_END
   584  
   585  	// Output:
   586  	// OK
   587  	// OK
   588  	// OK
   589  	// [0 0 0]
   590  	// [1 1 1]
   591  	// [2 2 2]
   592  	// [3 3 3]
   593  	// [4 4 4]
   594  	// rg:2:
   595  	//   [4 1.78]
   596  	// rg:3:
   597  	//   [4 0.74]
   598  	// rg:2:
   599  	//   unit: cm
   600  	//   [4 1.78]
   601  	// rg:3:
   602  	//   unit: in
   603  	//   [4 0.74]
   604  	// rg:4:
   605  	//   location: uk
   606  	//   unit: mm
   607  	//   Aggregators: map[aggregators:[]]
   608  	//   [[0 25] [1 18] [2 21]]
   609  	// rg:2:
   610  	//   location: us
   611  	//   Aggregators: map[aggregators:[]]
   612  	//   [[3 1.9] [2 2.3] [1 2.1]]
   613  	// rg:4:
   614  	//   location: uk
   615  	//   Aggregators: map[aggregators:[]]
   616  	//   [[3 19] [2 21] [1 18]]
   617  }
   618  
   619  func ExampleClient_timeseries_aggregation() {
   620  	ctx := context.Background()
   621  
   622  	rdb := redis.NewClient(&redis.Options{
   623  		Addr:     "localhost:6379",
   624  		Password: "", // no password set
   625  		DB:       0,  // use default DB
   626  	})
   627  
   628  	// REMOVE_START
   629  	// make sure we are working with fresh database
   630  	rdb.FlushDB(ctx)
   631  	rdb.Del(ctx, "rg:2")
   632  	// REMOVE_END
   633  
   634  	// Setup data for aggregation example
   635  	_, err := rdb.TSCreateWithArgs(ctx, "rg:2", &redis.TSOptions{
   636  		Labels: map[string]string{"location": "us", "unit": "cm"},
   637  	}).Result()
   638  	if err != nil {
   639  		panic(err)
   640  	}
   641  
   642  	_, err = rdb.TSMAdd(ctx, [][]interface{}{
   643  		{"rg:2", 0, 1.8},
   644  		{"rg:2", 1, 2.1},
   645  		{"rg:2", 2, 2.3},
   646  		{"rg:2", 3, 1.9},
   647  		{"rg:2", 4, 1.78},
   648  	}).Result()
   649  	if err != nil {
   650  		panic(err)
   651  	}
   652  
   653  	// STEP_START agg
   654  	res32, err := rdb.TSRangeWithArgs(
   655  		ctx,
   656  		"rg:2",
   657  		0,
   658  		math.MaxInt64,
   659  		&redis.TSRangeOptions{
   660  			Aggregator:     redis.Avg,
   661  			BucketDuration: 2,
   662  		},
   663  	).Result()
   664  	if err != nil {
   665  		panic(err)
   666  	}
   667  
   668  	fmt.Println(res32)
   669  	// >>> [{0 1.9500000000000002} {2 2.0999999999999996} {4 1.78}]
   670  	// STEP_END
   671  
   672  	// Output:
   673  	// [{0 1.9500000000000002} {2 2.0999999999999996} {4 1.78}]
   674  }
   675  func ExampleClient_timeseries_agg_bucket() {
   676  	ctx := context.Background()
   677  
   678  	rdb := redis.NewClient(&redis.Options{
   679  		Addr:     "localhost:6379",
   680  		Password: "", // no password set
   681  		DB:       0,  // use default DB
   682  	})
   683  
   684  	// REMOVE_START
   685  	// make sure we are working with fresh database
   686  	rdb.FlushDB(ctx)
   687  	rdb.Del(ctx, "sensor3")
   688  	// REMOVE_END
   689  
   690  	// STEP_START agg_bucket
   691  	res1, err := rdb.TSCreate(ctx, "sensor3").Result()
   692  	if err != nil {
   693  		panic(err)
   694  	}
   695  
   696  	fmt.Println(res1) // >>> OK
   697  
   698  	res2, err := rdb.TSMAdd(ctx, [][]interface{}{
   699  		{"sensor3", 10, 1000},
   700  		{"sensor3", 20, 2000},
   701  		{"sensor3", 30, 3000},
   702  		{"sensor3", 40, 4000},
   703  		{"sensor3", 50, 5000},
   704  		{"sensor3", 60, 6000},
   705  		{"sensor3", 70, 7000},
   706  	}).Result()
   707  	if err != nil {
   708  		panic(err)
   709  	}
   710  
   711  	fmt.Println(res2) // >>> [10 20 30 40 50 60 70]
   712  
   713  	res3, err := rdb.TSRangeWithArgs(
   714  		ctx,
   715  		"sensor3",
   716  		10,
   717  		70,
   718  		&redis.TSRangeOptions{
   719  			Aggregator:     redis.Min,
   720  			BucketDuration: 25,
   721  		},
   722  	).Result()
   723  	if err != nil {
   724  		panic(err)
   725  	}
   726  
   727  	fmt.Println(res3) // >>> [{0 1000} {25 3000} {50 5000}]
   728  	// STEP_END
   729  
   730  	// STEP_START agg_align
   731  	res4, err := rdb.TSRangeWithArgs(
   732  		ctx,
   733  		"sensor3",
   734  		10,
   735  		70,
   736  		&redis.TSRangeOptions{
   737  			Aggregator:     redis.Min,
   738  			BucketDuration: 25,
   739  			Align:          "START",
   740  		},
   741  	).Result()
   742  	if err != nil {
   743  		panic(err)
   744  	}
   745  
   746  	fmt.Println(res4) // >>> [{10 1000} {35 4000} {60 6000}]
   747  	// STEP_END
   748  
   749  	// Output:
   750  	// OK
   751  	// [10 20 30 40 50 60 70]
   752  	// [{0 1000} {25 3000} {50 5000}]
   753  	// [{10 1000} {35 4000} {60 6000}]
   754  }
   755  
   756  func ExampleClient_timeseries_aggmulti() {
   757  	ctx := context.Background()
   758  
   759  	rdb := redis.NewClient(&redis.Options{
   760  		Addr:     "localhost:6379",
   761  		Password: "", // no password set
   762  		DB:       0,  // use default DB
   763  	})
   764  
   765  	// REMOVE_START
   766  	// make sure we are working with fresh database
   767  	rdb.FlushDB(ctx)
   768  	rdb.Del(ctx, "wind:1", "wind:2", "wind:3", "wind:4")
   769  	// REMOVE_END
   770  
   771  	// STEP_START agg_multi
   772  	res37, err := rdb.TSCreateWithArgs(ctx, "wind:1", &redis.TSOptions{
   773  		Labels: map[string]string{"country": "uk"},
   774  	}).Result()
   775  	if err != nil {
   776  		panic(err)
   777  	}
   778  
   779  	fmt.Println(res37) // >>> OK
   780  
   781  	res38, err := rdb.TSCreateWithArgs(ctx, "wind:2", &redis.TSOptions{
   782  		Labels: map[string]string{"country": "uk"},
   783  	}).Result()
   784  	if err != nil {
   785  		panic(err)
   786  	}
   787  
   788  	fmt.Println(res38) // >>> OK
   789  
   790  	res39, err := rdb.TSCreateWithArgs(ctx, "wind:3", &redis.TSOptions{
   791  		Labels: map[string]string{"country": "us"},
   792  	}).Result()
   793  	if err != nil {
   794  		panic(err)
   795  	}
   796  
   797  	fmt.Println(res39) // >>> OK
   798  
   799  	res40, err := rdb.TSCreateWithArgs(ctx, "wind:4", &redis.TSOptions{
   800  		Labels: map[string]string{"country": "us"},
   801  	}).Result()
   802  	if err != nil {
   803  		panic(err)
   804  	}
   805  
   806  	fmt.Println(res40) // >>> OK
   807  
   808  	res41, err := rdb.TSMAdd(ctx, [][]interface{}{
   809  		{"wind:1", 1, 12},
   810  		{"wind:2", 1, 18},
   811  		{"wind:3", 1, 5},
   812  		{"wind:4", 1, 20},
   813  	}).Result()
   814  	if err != nil {
   815  		panic(err)
   816  	}
   817  
   818  	fmt.Println(res41) // >>> [1 1 1 1]
   819  
   820  	res42, err := rdb.TSMAdd(ctx, [][]interface{}{
   821  		{"wind:1", 2, 14},
   822  		{"wind:2", 2, 21},
   823  		{"wind:3", 2, 4},
   824  		{"wind:4", 2, 25},
   825  	}).Result()
   826  	if err != nil {
   827  		panic(err)
   828  	}
   829  
   830  	fmt.Println(res42) // >>> [2 2 2 2]
   831  
   832  	res43, err := rdb.TSMAdd(ctx, [][]interface{}{
   833  		{"wind:1", 3, 10},
   834  		{"wind:2", 3, 24},
   835  		{"wind:3", 3, 8},
   836  		{"wind:4", 3, 18},
   837  	}).Result()
   838  	if err != nil {
   839  		panic(err)
   840  	}
   841  
   842  	fmt.Println(res43) // >>> [3 3 3 3]
   843  
   844  	// The result pairs contain the timestamp and the maximum sample value
   845  	// for the country at that timestamp.
   846  	res44, err := rdb.TSMRangeWithArgs(
   847  		ctx,
   848  		0,
   849  		math.MaxInt64,
   850  		[]string{"country=(us,uk)"},
   851  		&redis.TSMRangeOptions{
   852  			GroupByLabel: "country",
   853  			Reducer:      "max",
   854  		},
   855  	).Result()
   856  	if err != nil {
   857  		panic(err)
   858  	}
   859  
   860  	res44Keys := slices.Collect(maps.Keys(res44))
   861  	sort.Strings(res44Keys)
   862  
   863  	for _, k := range res44Keys {
   864  		labels := res44[k][0].(map[interface{}]interface{})
   865  		labelKeys := make([]string, 0, len(labels))
   866  
   867  		for lk := range labels {
   868  			labelKeys = append(labelKeys, lk.(string))
   869  		}
   870  
   871  		sort.Strings(labelKeys)
   872  
   873  		fmt.Printf("%v:\n", k)
   874  
   875  		for _, lk := range labelKeys {
   876  			fmt.Printf("  %v: %v\n", lk, labels[lk])
   877  		}
   878  
   879  		fmt.Printf("  %v\n", res44[k][1])
   880  		fmt.Printf("  %v\n", res44[k][2])
   881  		fmt.Printf("  %v\n", res44[k][3])
   882  	}
   883  	// >>> country=uk:
   884  	// >>>   map[reducers:[max]]
   885  	// >>>   map[sources:[wind:1 wind:2]]
   886  	// >>>   [[1 18] [2 21] [3 24]]
   887  	// >>> country=us:
   888  	// >>>   map[reducers:[max]]
   889  	// >>>   map[sources:[wind:3 wind:4]]
   890  	// >>>   [[1 20] [2 25] [3 18]]
   891  
   892  	// The result pairs contain the timestamp and the average sample value
   893  	// for the country at that timestamp.
   894  	res45, err := rdb.TSMRangeWithArgs(
   895  		ctx,
   896  		0,
   897  		math.MaxInt64,
   898  		[]string{"country=(us,uk)"},
   899  		&redis.TSMRangeOptions{
   900  			GroupByLabel: "country",
   901  			Reducer:      "avg",
   902  		},
   903  	).Result()
   904  	if err != nil {
   905  		panic(err)
   906  	}
   907  
   908  	res45Keys := slices.Collect(maps.Keys(res45))
   909  	sort.Strings(res45Keys)
   910  
   911  	for _, k := range res45Keys {
   912  		labels := res45[k][0].(map[interface{}]interface{})
   913  		labelKeys := make([]string, 0, len(labels))
   914  
   915  		for lk := range labels {
   916  			labelKeys = append(labelKeys, lk.(string))
   917  		}
   918  
   919  		sort.Strings(labelKeys)
   920  
   921  		fmt.Printf("%v:\n", k)
   922  
   923  		for _, lk := range labelKeys {
   924  			fmt.Printf("  %v: %v\n", lk, labels[lk])
   925  		}
   926  
   927  		fmt.Printf("  %v\n", res45[k][1])
   928  		fmt.Printf("  %v\n", res45[k][2])
   929  		fmt.Printf("  %v\n", res45[k][3])
   930  	}
   931  	// >>> country=uk:
   932  	// >>>   map[reducers:[avg]]
   933  	// >>>   map[sources:[wind:1 wind:2]]
   934  	// >>>   [[1 15] [2 17.5] [3 17]]
   935  	// >>> country=us:
   936  	// >>>   map[reducers:[avg]]
   937  	// >>>   map[sources:[wind:3 wind:4]]
   938  	// >>>   [[1 12.5] [2 14.5] [3 13]]
   939  	// STEP_END
   940  
   941  	// Output:
   942  	// OK
   943  	// OK
   944  	// OK
   945  	// OK
   946  	// [1 1 1 1]
   947  	// [2 2 2 2]
   948  	// [3 3 3 3]
   949  	// country=uk:
   950  	//   map[reducers:[max]]
   951  	//   map[sources:[wind:1 wind:2]]
   952  	//   [[1 18] [2 21] [3 24]]
   953  	// country=us:
   954  	//   map[reducers:[max]]
   955  	//   map[sources:[wind:3 wind:4]]
   956  	//   [[1 20] [2 25] [3 18]]
   957  	// country=uk:
   958  	//   map[reducers:[avg]]
   959  	//   map[sources:[wind:1 wind:2]]
   960  	//   [[1 15] [2 17.5] [3 17]]
   961  	// country=us:
   962  	//   map[reducers:[avg]]
   963  	//   map[sources:[wind:3 wind:4]]
   964  	//   [[1 12.5] [2 14.5] [3 13]]
   965  }
   966  
   967  func ExampleClient_timeseries_compaction() {
   968  	ctx := context.Background()
   969  
   970  	rdb := redis.NewClient(&redis.Options{
   971  		Addr:     "localhost:6379",
   972  		Password: "", // no password set
   973  		DB:       0,  // use default DB
   974  	})
   975  
   976  	// REMOVE_START
   977  	// make sure we are working with fresh database
   978  	rdb.FlushDB(ctx)
   979  	rdb.Del(ctx, "hyg:1", "hyg:compacted")
   980  	// REMOVE_END
   981  
   982  	// STEP_START create_compaction
   983  	res45, err := rdb.TSCreate(ctx, "hyg:1").Result()
   984  	if err != nil {
   985  		panic(err)
   986  	}
   987  
   988  	fmt.Println(res45) // >>> OK
   989  
   990  	res46, err := rdb.TSCreate(ctx, "hyg:compacted").Result()
   991  	if err != nil {
   992  		panic(err)
   993  	}
   994  
   995  	fmt.Println(res46) // >>> OK
   996  
   997  	res47, err := rdb.TSCreateRule(
   998  		ctx, "hyg:1", "hyg:compacted", redis.Min, 3,
   999  	).Result()
  1000  	if err != nil {
  1001  		panic(err)
  1002  	}
  1003  
  1004  	fmt.Println(res47) // >>> OK
  1005  
  1006  	res48, err := rdb.TSInfo(ctx, "hyg:1").Result()
  1007  	if err != nil {
  1008  		panic(err)
  1009  	}
  1010  
  1011  	fmt.Println(res48["rules"]) // >>> [[hyg:compacted 3 MIN 0]]
  1012  
  1013  	res49, err := rdb.TSInfo(ctx, "hyg:compacted").Result()
  1014  	if err != nil {
  1015  		panic(err)
  1016  	}
  1017  
  1018  	fmt.Println(res49["sourceKey"]) // >>> hyg:1
  1019  	// STEP_END
  1020  
  1021  	// STEP_START comp_add
  1022  	res50, err := rdb.TSMAdd(ctx, [][]interface{}{
  1023  		{"hyg:1", 0, 75},
  1024  		{"hyg:1", 1, 77},
  1025  		{"hyg:1", 2, 78},
  1026  	}).Result()
  1027  	if err != nil {
  1028  		panic(err)
  1029  	}
  1030  
  1031  	fmt.Println(res50) // >>> [0 1 2]
  1032  
  1033  	res51, err := rdb.TSRange(
  1034  		ctx, "hyg:compacted", 0, math.MaxInt64,
  1035  	).Result()
  1036  	if err != nil {
  1037  		panic(err)
  1038  	}
  1039  
  1040  	fmt.Println(res51) // >>> []
  1041  
  1042  	res52, err := rdb.TSAdd(ctx, "hyg:1", 3, 79).Result()
  1043  	if err != nil {
  1044  		panic(err)
  1045  	}
  1046  
  1047  	fmt.Println(res52) // >>> 3
  1048  
  1049  	res53, err := rdb.TSRange(
  1050  		ctx, "hyg:compacted", 0, math.MaxInt64,
  1051  	).Result()
  1052  	if err != nil {
  1053  		panic(err)
  1054  	}
  1055  
  1056  	fmt.Println(res53) // >>> [{0 75}]
  1057  	// STEP_END
  1058  
  1059  	// Output:
  1060  	// OK
  1061  	// OK
  1062  	// OK
  1063  	// map[hyg:compacted:[3 MIN 0]]
  1064  	// hyg:1
  1065  	// [0 1 2]
  1066  	// []
  1067  	// 3
  1068  	// [{0 75}]
  1069  }
  1070  
  1071  func ExampleClient_timeseries_delete() {
  1072  	ctx := context.Background()
  1073  
  1074  	rdb := redis.NewClient(&redis.Options{
  1075  		Addr:     "localhost:6379",
  1076  		Password: "", // no password set
  1077  		DB:       0,  // use default DB
  1078  	})
  1079  
  1080  	// REMOVE_START
  1081  	// make sure we are working with fresh database
  1082  	rdb.FlushDB(ctx)
  1083  	rdb.Del(ctx, "thermometer:1")
  1084  	// Setup initial data
  1085  	rdb.TSCreate(ctx, "thermometer:1")
  1086  	rdb.TSMAdd(ctx, [][]interface{}{
  1087  		{"thermometer:1", 1, 9.2},
  1088  		{"thermometer:1", 2, 9.9},
  1089  	})
  1090  	// REMOVE_END
  1091  
  1092  	// STEP_START del
  1093  	res54, err := rdb.TSInfo(ctx, "thermometer:1").Result()
  1094  	if err != nil {
  1095  		panic(err)
  1096  	}
  1097  
  1098  	fmt.Println(res54["totalSamples"])   // >>> 2
  1099  	fmt.Println(res54["firstTimestamp"]) // >>> 1
  1100  	fmt.Println(res54["lastTimestamp"])  // >>> 2
  1101  
  1102  	res55, err := rdb.TSAdd(ctx, "thermometer:1", 3, 9.7).Result()
  1103  	if err != nil {
  1104  		panic(err)
  1105  	}
  1106  
  1107  	fmt.Println(res55) // >>> 3
  1108  
  1109  	res56, err := rdb.TSInfo(ctx, "thermometer:1").Result()
  1110  	if err != nil {
  1111  		panic(err)
  1112  	}
  1113  
  1114  	fmt.Println(res56["totalSamples"])   // >>> 3
  1115  	fmt.Println(res56["firstTimestamp"]) // >>> 1
  1116  	fmt.Println(res56["lastTimestamp"])  // >>> 3
  1117  
  1118  	res57, err := rdb.TSDel(ctx, "thermometer:1", 1, 2).Result()
  1119  	if err != nil {
  1120  		panic(err)
  1121  	}
  1122  
  1123  	fmt.Println(res57) // >>> 2
  1124  
  1125  	res58, err := rdb.TSInfo(ctx, "thermometer:1").Result()
  1126  	if err != nil {
  1127  		panic(err)
  1128  	}
  1129  
  1130  	fmt.Println(res58["totalSamples"])   // >>> 1
  1131  	fmt.Println(res58["firstTimestamp"]) // >>> 3
  1132  	fmt.Println(res58["lastTimestamp"])  // >>> 3
  1133  
  1134  	res59, err := rdb.TSDel(ctx, "thermometer:1", 3, 3).Result()
  1135  	if err != nil {
  1136  		panic(err)
  1137  	}
  1138  
  1139  	fmt.Println(res59) // >>> 1
  1140  
  1141  	res60, err := rdb.TSInfo(ctx, "thermometer:1").Result()
  1142  	if err != nil {
  1143  		panic(err)
  1144  	}
  1145  
  1146  	fmt.Println(res60["totalSamples"]) // >>> 0
  1147  	// STEP_END
  1148  
  1149  	// Output:
  1150  	// 2
  1151  	// 1
  1152  	// 2
  1153  	// 3
  1154  	// 3
  1155  	// 1
  1156  	// 3
  1157  	// 2
  1158  	// 1
  1159  	// 3
  1160  	// 3
  1161  	// 1
  1162  	// 0
  1163  }
  1164  

View as plain text