All Products
Search
Document Center

Time Series Database:Query multi-value data

Last Updated:Mar 30, 2026

Queries multivariate data points — data stored with multiple fields per metric — using the /api/mquery endpoint. Use /api/query for univariate data instead.

Important

The write and query paths differ by data model. Use /api/mput to write multivariate data and /api/mquery to query it. Use /api/put and /api/query for univariate data. The two models are not interchangeable.

Request

Endpoint

Path Method
/api/mquery POST

Request body parameters

Parameter Type Required Default Description
start Long Yes Start time. Accepts Unix timestamps in seconds or milliseconds. See Timestamp units.
end Long No Current server time End time. Accepts Unix timestamps in seconds or milliseconds. See Timestamp units.
queries Array Yes Array of subquery objects. See Subquery parameters.
msResolution Boolean No false When true, returns timestamps in milliseconds for data points stored in seconds. Has no effect on data stored in milliseconds — those always return millisecond timestamps.
hint Object No Query hint to limit index usage. Requires TSDB V2.6.1 or later. See Query hints.

Subquery parameters

Each object in the queries array supports the following parameters:

Parameter Type Required Default Description
metric String Yes The metric name.
fields Array Yes Array of field query objects. See Field query parameters.
rate Boolean No false Calculates the growth rate between consecutive values: (Vt − Vt-1) / (t − t-1).
delta Boolean No false Calculates the delta between consecutive values: Vt − Vt-1. See Delta operator.
limit Integer No 0 Maximum data points to return per timeline. 0 means no limit. Applies to paged multivariate queries only — not to individual field queries.
offset Integer No 0 Number of data points to skip per timeline. Use with limit for pagination.
dpValue String No Filters returned data points by value. Supported operators: >, <, =, <=, >=, !=. When set to a string, only = and != are supported.
preDpValue String No Filters data points during the scan, before aggregation. Unlike dpValue (which filters post-aggregation results), preDpValue excludes matching data points from all queries and calculations.
downsample String No Downsampling expression. See Downsampling.
tags Object No Tag key-value pairs to filter data. Conflicts with filters — if both are specified, the one appearing later in the JSON takes effect.
filters Array No Filter objects for tag-based filtering. Conflicts with tags. See Filters.
hint Object No Subquery-level query hint. Overrides the top-level hint for this subquery.

Field query parameters

Each object in the fields array supports the following parameters:

Parameter Type Required Default Description
aggregator String Yes Aggregate function to apply. Set to none to skip aggregation. If specified in any field query, must be specified in all field queries within the same subquery.
field String Yes Field name. Use * to query all fields for the metric.
alias String No Alias for the returned field name.
downsample String No Downsampling expression. All field queries in the same subquery must use the same interval.
rate Boolean No false Calculates the growth rate for this field.
dpValue String No Filters returned values for this field. Supported operators: >, <, =, <=, >=, !=. Applied independently per field — does not apply across fields.
where String No Used only when field is *. Filters fields before returning results, using the same logic as dpValue. Example: speed>10.
A single query can include at most 200 field values across all subqueries. To count: add up the number of field values across all fields arrays in all subqueries.

Timestamp units

TSDB determines the timestamp unit from the numeric value:

Range Unit Corresponding date range
[4284768, 9999999999] Seconds 1970-02-20 to 2286-11-21
[10000000000, 9999999999999] Milliseconds 1970-04-27 to 2286-11-21
Outside both ranges Invalid

These rules apply to /api/put, /api/mput, /api/query, and /api/mquery.

To query data at a single point in time, set start and end to the same value. For example: "start": 1356998400, "end": 1356998400.

Sample request

POST /api/mquery

{
  "start": 1346846400,
  "end": 1346846411,
  "msResolution": true,
  "queries": [
    {
      "metric": "wind",
      "fields": [
        {
          "field": "speed",
          "aggregator": "sum",
          "downsample": "2s-last",
          "alias": "speed_sum"
        },
        {
          "field": "*",
          "aggregator": "sum",
          "downsample": "2s-count",
          "where": "speed>10"
        }
      ]
    }
  ]
}

Downsampling

Downsampling aggregates data over fixed time intervals, reducing the number of returned data points. Use it when querying long time ranges where per-second granularity is unnecessary.

Expression format

<interval><units>-<aggregator>[-fill policy]

`interval`: A numeric value such as 5 or 60. Use 0all to aggregate all data points in the range into a single value.

`units`:

Unit Meaning
s Seconds
m Minutes
h Hours
d Days
n Months
y Years

Add c to use calendar alignment (for example, 1dc represents the 24-hour period from 00:00 of the current day). Without c, timestamps align using: aligned timestamp = data timestamp − (data timestamp % interval).

`aggregator` options:

Operator Description
avg Average value
count Number of data points
first First value (aligned timestamp)
last Last value (aligned timestamp)
min Minimum value (aligned timestamp)
max Maximum value (aligned timestamp)
sum Sum of values
zimsum Sum of values
rfirst First value with original (unaligned) timestamp
rlast Last value with original (unaligned) timestamp
rmin Minimum value with original (unaligned) timestamp
rmax Maximum value with original (unaligned) timestamp
The rfirst, rlast, rmin, and rmax operators cannot be used with a fill policy.

Time window expansion

After specifying downsample, TSDB automatically extends the query range by one interval on each side. For example, if the range is [1346846401, 1346846499] and the interval is 5m, the actual query range becomes [1346846101, 1346846799].

Fill policy

When a time bucket contains no data points, a fill policy determines what value to report for that bucket.

Fill policy Value
none No values are filled. This is the default value.
nan NaN
null null
zero 0
linear The value that is calculated based on linear interpolation.
previous The previous value.
near The adjacent value.
after The next value.
fixed A user-specified fixed value. See Fixed fill policy.

Fixed fill policy

Append a fixed value to the format using #:

<interval><units>-<aggregator>-fixed#<number>

The fixed value can be positive or negative. Examples: 1h-sum-fixed#6, 1h-avg-fixed#-8.

Downsampling examples

Three valid downsampling expressions: 1m-avg, 1h-sum-zero, 1h-sum-near.

Important

The downsample parameter is optional in field queries. To disable downsampling explicitly, set it to null or an empty string: {"downsample": null} or {"downsample": ""}. If one field query in a subquery specifies downsample, all field queries in that subquery must specify the same interval.

Aggregator

After downsampling, multiple timelines may share aligned timestamps. The aggregator merges those timelines into one by aggregating values at each timestamp. If only one timeline exists, no aggregation is performed.

Important

aggregator is required in all field queries. Set it to none to skip aggregation. If any field query in a subquery specifies aggregator, all field queries in that subquery must specify it. Partial aggregation within a subquery is not supported.

Interpolation

When aggregating multiple timelines, if a timeline has no value at an aligned timestamp and another timeline does, TSDB interpolates a value for the missing timeline. This only applies when no fill policy is set.

The interpolation method depends on the aggregator:

Aggregator Interpolation method
avg Linear interpolation
count Interpolates zero
min Linear interpolation
max Linear interpolation
mimmin Interpolates the maximum value
mimmax Interpolates the minimum value
none Interpolates zero
sum Linear interpolation
zimsum Interpolates zero

Delta operator

When delta is set to true, the value in each dps key-value pair is replaced by the calculated delta (Vt − Vt-1).

Important

If the original result contains n key-value pairs, the delta result contains n-1 pairs — the first pair is dropped because no preceding value exists to compute against. The delta operator also applies after downsampling.

`deltaOptions` parameters

Parameter Type Required Default Description
counter Boolean No false Treats metric values as monotonically increasing or decreasing counters. The server does not validate monotonicity.
counterMax Integer No Maximum allowed absolute delta. Deltas exceeding this threshold are considered abnormal and either dropped or reset to 0. Only applies when counter is true.
dropReset Boolean No false Requires counterMax. When an abnormal delta is detected, true drops it; false (or omitted) resets it to 0.

Example

{
  "start": 1346046400,
  "end": 1347056500,
  "queries": [
    {
      "metric": "sys.cpu.0",
      "aggregator": "none",
      "downsample": "5s-avg",
      "delta": true,
      "deltaOptions": {
        "counter": true,
        "counterMax": 100
      },
      "dpValue": ">=50",
      "tags": {
        "host": "localhost",
        "appName": "hitsdb"
      }
    }
  ]
}

Pagination with limit and offset

Use limit and offset to paginate results across multiple timelines.

  • limit: Maximum data points per timeline per page. 0 means no limit (default).

  • offset: Number of data points to skip per timeline.

Important

Neither limit nor offset can be negative. These parameters apply to paged multivariate queries and cannot be used for single-field queries.

Example: To return data points ranked 1001 to 1500, set limit to 500 and offset to 1000.

{
  "start": 1346846400,
  "end": 1346846411,
  "msResolution": true,
  "queries": [
    {
      "metric": "wind",
      "fields": [
        {
          "field": "*",
          "aggregator": "sum",
          "downsample": "2s-count"
        }
      ],
      "filters": [
        {
          "filter": "IOTE_8859_0005|IOTE_8859_0004",
          "tagk": "sensor",
          "type": "literal_or"
        }
      ],
      "limit": 500,
      "offset": 1000
    }
  ]
}

Filters

Filters select which timelines to include in a query based on tag values. The filters parameter conflicts with tags — if both appear in the JSON, the one at the latter position takes effect.

Filter object parameters

Parameter Type Required Default Description
type String Yes Filter type. See filter types below.
tagk String Yes Tag key to filter on.
filter String Yes Filter expression.
groupBy Boolean No false Groups results by tag values.

Filter types

Type Example Description
literal_or web01|web02 The values of each tagv are aggregated. This filter is case-sensitive.
wildcard *.example.com The tag values that contain the specified wildcard for each tagv are aggregated. This filter is case-sensitive.

You can also specify filters using tag shorthand:

  • tagk = *: Groups all tag values for that key and aggregates per distinct value.

  • tagk = tagv1|tagv2: Groups tagv1 values together and tagv2 values together.

Example with filters

{
  "start": 1346846400,
  "end": 1346846411,
  "msResolution": true,
  "queries": [
    {
      "metric": "wind",
      "fields": [
        {
          "field": "speed",
          "aggregator": "none",
          "alias": "column_speed"
        },
        {
          "field": "*",
          "aggregator": "none",
          "alias": "column_"
        }
      ],
      "filters": [
        {
          "filter": "IOTE_8859_0005|IOTE_8859_0004",
          "tagk": "sensor",
          "type": "literal_or"
        }
      ]
    }
  ]
}

Response

A successful query returns HTTP 200 with a JSON array.

Response fields

Field Description
metric The metric name.
columns The columns returned.
tags Tags whose values were not aggregated (applied as exact filters).
aggregatedTags Tags whose values were aggregated across timelines.
values Array of tuples. Each tuple corresponds to a row of data keyed by columns.

Example: aggregator set to `none`

Returns one result object per matched timeline (no aggregation across sensors):

[
  {
    "metric": "wind",
    "columns": [
      "timestamp",
      "column_speed",
      "column_description",
      "column_direction",
      "column_level",
      "column_speed"
    ],
    "tags": {
      "city": "hangzhou",
      "country": "china",
      "province": "zhejiang",
      "sensor": "IOTE_8859_0005"
    },
    "aggregatedTags": [],
    "values": [
      [1346846406000, null, "Fresh breeze", "East", 0.5, null],
      [1346846407000, null, "Fresh breeze", "South", 1.5, null]
    ]
  },
  {
    "metric": "wind",
    "columns": [
      "timestamp",
      "column_speed",
      "column_description",
      "column_direction",
      "column_level",
      "column_speed"
    ],
    "tags": {
      "city": "hangzhou",
      "country": "china",
      "province": "zhejiang",
      "sensor": "IOTE_8859_0004"
    },
    "aggregatedTags": [],
    "values": [
      [1346846400000, 40.4, "Fresh breeze", "East", 0.4, 40.4],
      [1346846401000, 41.4, "Fresh breeze", "South", 1.4, 41.4],
      [1346846402000, 42.4, "Fresh breeze", "West", 2.4, 42.4],
      [1346846403000, 43.4, "Fresh breeze", "North", 3.4, 43.4]
    ]
  }
]

Example: aggregator set to `avg`

Returns average wind speed and level aggregated across all sensors in the city:

[
  {
    "metric": "wind",
    "columns": ["timestamp", "avg_level", "avg_speed"],
    "tags": {
      "city": "hangzhou"
    },
    "aggregatedTags": ["country", "province", "sensor"],
    "values": [
      [1346846400000, 0.25, 40.25],
      [1346846401000, 1.25, 41.25],
      [1346846402000, 2.5, 42.5],
      [1346846411000, 5.5, null]
    ]
  }
]

Query hints

A query hint tells TSDB which tag indexes to use (or skip) when resolving timelines, reducing response time when the set of timelines targeted by one set of tags is a known subset of another.

Important

Requires TSDB V2.6.1 or later.

Format

Specify tag key names under hint.tagk with values 0 (skip index) or 1 (use index). All values in a single hint must be either all 0 or all 1 — mixing them returns an error.

Hint scoped to a subquery

{
  "queries": [
    {
      "metric": "demo.mf",
      "tags": {
        "sensor": "IOTE_8859_0001",
        "city": "hangzhou",
        "province": "zhejiang",
        "country": "china"
      },
      "fields": ["speed"],
      "hint": {
        "tagk": { "dc": 1 }
      }
    }
  ]
}

Hint scoped to the entire query

{
  "queries": [
    {
      "metric": "demo.mf",
      "tags": {
        "sensor": "IOTE_8859_0001",
        "city": "hangzhou",
        "province": "zhejiang",
        "country": "china"
      },
      "fields": ["speed"]
    }
  ],
  "hint": {
    "tagk": { "dc": 1 }
  }
}

Error: mixing 0 and 1 in the same hint

{
  "start": 1346846400,
  "end": 1346846400,
  "queries": [
    {
      "aggregator": "none",
      "metric": "sys.cpu.nice",
      "tags": {
        "dc": "lga",
        "host": "web01"
      }
    }
  ],
  "hint": {
    "tagk": {
      "dc": 1,
      "host": 0
    }
  }
}

Returns:

{
  "error": {
    "code": 400,
    "message": "The value of hint should only be 0 or 1, and there should not be both 0 and 1",
    "details": "TSQuery(start_time=1346846400, end_time=1346846400, subQueries[TSSubQuery(metric=sys.cpu.nice, filters=[filter_name=literal_or, tagk=dc, literals=[lga], group_by=true, filter_name=literal_or, tagk=host, literals=[web01], group_by=true], tsuids=[], agg=none, downsample=null, ds_interval=0, rate=false, rate_options=null, delta=false, delta_options=null, top=0, granularity=null, granularityDownsample=null, explicit_tags=explicit_tags, index=0, realTimeSeconds=-1, useData=auto, limit=0, offset=0, dpValue=null, preDpValue=null, startTime=1346846400000, endTime=1346846400000, Query_ID=null)] padding=false, no_annotations=false, with_global_annotations=false, show_tsuids=false, ms_resolution=false, options=[])"
  }
}

Error: invalid hint value

{
  "start": 1346846400,
  "end": 1346846400,
  "queries": [
    {
      "aggregator": "none",
      "metric": "sys.cpu.nice",
      "tags": {
        "dc": "lga",
        "host": "web01"
      }
    }
  ],
  "hint": {
    "tagk": {
      "dc": 100
    }
  }
}

Returns:

{
  "error": {
    "code": 400,
    "message": "The value of hint can only be 0 or 1, and it is detected that '100' is passed in",
    "details": "TSQuery(start_time=1346846400, end_time=1346846400, subQueries[TSSubQuery(metric=sys.cpu.nice, filters=[filter_name=literal_or, tagk=dc, literals=[lga], group_by=true, filter_name=literal_or, tagk=host, literals=[web01], group_by=true], tsuids=[], agg=none, downsample=null, ds_interval=0, rate=false, rate_options=null, delta=false, delta_options=null, top=0, granularity=null, granularityDownsample=null, explicit_tags=explicit_tags, index=0, realTimeSeconds=-1, useData=auto, limit=0, offset=0, dpValue=null, preDpValue=null, startTime=1346846400000, endTime=1346846400000, Query_ID=null)] padding=false, no_annotations=false, with_global_annotations=false, show_tsuids=false, ms_resolution=false, options=[])"
  }
}