Skip to main content

Query & aggregate time-series

Read raw datapoints back for a window, then roll them up to fixed buckets (hourly averages, daily maxima) for a chart or report. Aggregates and the bucket size are part of the retrieve filter — no separate endpoint.

Raw datapoints for a window

import java.time.ZonedDateTime;

var filter = new RetrieveFilter();
filter.setExternalId("engine_temperature");
filter.setStart(ZonedDateTime.now().minusDays(1));
filter.setEnd(ZonedDateTime.now());
filter.setLimit(10_000);

var request = new DataRetriever<RetrieveFilter>();
request.setItems(List.of(filter));

client.timeseries().retrieve(request).getItems().forEach(series ->
series.getDatapoints().forEach(p ->
System.out.println(p.getTimestamp() + " = " + p.getValue())));

Hourly averages

Set aggregates and granularity and the server returns one value per bucket.

var filter = new RetrieveFilter();
filter.setExternalId("engine_temperature");
filter.setStart(ZonedDateTime.now().minusDays(1));
filter.setEnd(ZonedDateTime.now());
filter.setAggregates(List.of("avg", "max"));
filter.setGranularity("1h");

var request = new DataRetriever<RetrieveFilter>();
request.setItems(List.of(filter));

// NOTE: Java can't read aggregate values yet — getValue() returns null here (see warning below)
client.timeseries().retrieve(request).getItems()
.forEach(s -> s.getDatapoints().forEach(p ->
System.out.println(p.getTimestamp() + " = " + p.getValue())));
Common aggregates

avg, min, max, sum. Granularity is a number plus a unit — 30s, 5m, 1h, 1d. The Python and Rust datapoint types expose each requested aggregate as its own field — min/max/sum by name, and avg read back on .average (dp.average, dp.max, …).

Java aggregate reads

The Java client does not expose aggregate values yet: getValue() returns null for aggregated datapoints (the server sends avg/max/… as named fields, but the Java datapoint type carries only timestamp/value). For now use Python or Rust for aggregates — or in Java, fetch raw datapoints and aggregate them in your application.

Paging large windows

A wide window can exceed one response. When the result carries a cursor, pass it back to fetch the next page.

String cursor = null;
do {
var filter = new RetrieveFilter();
filter.setExternalId("engine_temperature");
filter.setStart(start);
filter.setEnd(end);
filter.setCursor(cursor);

var request = new DataRetriever<RetrieveFilter>();
request.setItems(List.of(filter));

var page = client.timeseries().retrieve(request).getItems().get(0);
page.getDatapoints().forEach(p -> handle(p));
cursor = page.getNextCursor();
} while (cursor != null);