Queries multivariate data points — data stored with multiple fields per metric — using the /api/mquery endpoint. Use /api/query for univariate data instead.
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 offieldvalues across allfieldsarrays 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 |
Therfirst,rlast,rmin, andrmaxoperators 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.
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.
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).
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.0means no limit (default). -
offset: Number of data points to skip per timeline.
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: Groupstagv1values together andtagv2values 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.
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=[])"
}
}