Skip to main content

Persisted Queries

Persisted queries are saved query definitions stored as runtime entities. Instead of specifying all query parameters every time, you create a query definition once and execute it by its rtId. This is useful for dashboard widgets, recurring reports, and any scenario where the same query needs to be executed repeatedly.

Query Types

There are four persisted query types, corresponding to the four transient query types:

CK TypePurposeKey Fields
System/StreamDataSimpleQueryRaw time-series rowscolumns (string array), sorting
System/StreamDataAggregationQueryAggregated valuescolumns (with aggregation type)
System/StreamDataGroupingAggregationQueryGrouped aggregationgroupingColumns, columns (with aggregation type)
System/StreamDataDownsamplingQueryTime-bucketed aggregationcolumns (with aggregation type), required from/to/limit

Common Fields

All persisted query types share these configuration fields:

FieldTypeDescription
nameStringDisplay name for the query
descriptionStringOptional description
queryCkTypeIdStringThe CK type to query (e.g., "Industry.Energy/EnergyMeter")
navigationFilterModeStringFilter mode for runtime navigation
rtIds[String]Optional: scope to specific runtime entity IDs
fromDateTimeOptional: start of time range
toDateTimeOptional: end of time range
limitIntOptional: maximum rows to return
fieldFilter[FieldFilter]Optional: field-level comparison filters
note

Persisted queries use the CK-generated AggregationTypes enum with values COUNT, MINIMUM, MAXIMUM, AVERAGE, and SUM. This differs from the transient query AggregationType enum which uses the short forms AVG, MIN, MAX, COUNT, and SUM.


Creating Persisted Queries

Simple Query

Creates a saved query that retrieves raw time-series rows with column selection.

mutation {
runtime {
systemStreamDataSimpleQuerys {
create(entities: [
{
name: "Voltage readings last 24h"
description: "Raw voltage data for all energy meters"
queryCkTypeId: "Industry.Energy/EnergyMeter"
columns: ["voltage", "power"]
from: "2024-03-21T00:00:00Z"
to: "2024-03-22T00:00:00Z"
limit: 5000
sorting: [
{ attributePath: "timestamp", sortOrder: DESCENDING }
]
}
]) {
rtId
ckTypeId
name
description
queryCkTypeId
columns
from
to
limit
sorting {
attributePath
sortOrder
}
fieldFilter {
attributePath
operator
comparisonValue
}
}
}
}
}

The response includes the rtId of the newly created query — use this to execute it later.

Aggregation Query

Creates a saved aggregation query with specified aggregation functions per column.

mutation {
runtime {
systemStreamDataAggregationQuerys {
create(entities: [
{
name: "Energy meter statistics"
description: "Average, min, and max voltage"
queryCkTypeId: "Industry.Energy/EnergyMeter"
columns: [
{ attributePath: "voltage", aggregationType: AVERAGE },
{ attributePath: "voltage", aggregationType: MINIMUM },
{ attributePath: "voltage", aggregationType: MAXIMUM }
]
from: "2024-03-21T00:00:00Z"
to: "2024-03-22T00:00:00Z"
}
]) {
rtId
ckTypeId
name
queryCkTypeId
columns {
aggregationType
attributePath
}
}
}
}
}

Grouping Aggregation Query

Creates a saved query that aggregates values grouped by one or more columns.

mutation {
runtime {
systemStreamDataGroupingAggregationQuerys {
create(entities: [
{
name: "Average voltage per meter"
description: "Grouped by entity"
queryCkTypeId: "Industry.Energy/EnergyMeter"
groupingColumns: ["rtId"]
columns: [
{ attributePath: "voltage", aggregationType: AVERAGE },
{ attributePath: "power", aggregationType: MAXIMUM }
]
}
]) {
rtId
ckTypeId
name
queryCkTypeId
groupingColumns
columns {
aggregationType
attributePath
}
}
}
}
}

Downsampling Query

Creates a saved downsampling query. The from, to, and limit fields define the time range and bucket count.

mutation {
runtime {
systemStreamDataDownsamplingQuerys {
create(entities: [
{
name: "Hourly voltage trend"
description: "24h downsampled to hourly buckets"
queryCkTypeId: "Industry.Energy/EnergyMeter"
columns: [
{ attributePath: "voltage", aggregationType: AVERAGE },
{ attributePath: "voltage", aggregationType: MINIMUM },
{ attributePath: "voltage", aggregationType: MAXIMUM }
]
from: "2024-03-21T00:00:00Z"
to: "2024-03-22T00:00:00Z"
limit: 24
}
]) {
rtId
ckTypeId
name
queryCkTypeId
columns {
aggregationType
attributePath
}
from
to
limit
}
}
}
}

Executing Persisted Queries

Execute a saved query by passing its rtId. Each query type has its own execution endpoint.

Simple Query

query {
streamData {
streamDataQuery(
rtId: "67e1a2b3c4d5e6f7a8b9c0d1"
first: 100
) {
totalCount
pageInfo {
hasNextPage
endCursor
}
items {
rtId
ckTypeId
timestamp
rtWellKnownName
cells {
items {
attributePath
value
}
}
}
}
}
}

Aggregation Query

query {
streamData {
streamDataAggregationQuery(
rtId: "67e1a2b3c4d5e6f7a8b9c0d2"
) {
totalCount
items {
cells {
items {
attributePath
value
}
}
}
}
}
}

Grouping Aggregation Query

query {
streamData {
streamDataGroupingAggregationQuery(
rtId: "67e1a2b3c4d5e6f7a8b9c0d3"
) {
totalCount
items {
cells {
items {
attributePath
value
}
}
}
}
}
}

Downsampling Query

query {
streamData {
streamDataDownsamplingQuery(
rtId: "67e1a2b3c4d5e6f7a8b9c0d4"
) {
totalCount
items {
timestamp
cells {
items {
attributePath
value
}
}
}
}
}
}

Overriding Parameters at Execution Time

All persisted query execution endpoints accept an optional arg parameter of type StreamDataArguments. This allows you to override the saved time range and limit at execution time without modifying the query definition.

query {
streamData {
streamDataQuery(
rtId: "67e1a2b3c4d5e6f7a8b9c0d1"
arg: {
queryMode: DEFAULT
from: "2024-03-20T00:00:00Z"
to: "2024-03-21T00:00:00Z"
limit: 10000
}
first: 100
) {
totalCount
items {
timestamp
cells {
items {
attributePath
value
}
}
}
}
}
}

The simple query execution also supports sortOrder to override sorting at execution time:

streamDataQuery(
rtId: "67e1a2b3c4d5e6f7a8b9c0d1"
arg: { queryMode: DEFAULT }
sortOrder: [{ attributePath: "timestamp", sortOrder: ASCENDING }]
)

Retrieving Query Details

Retrieve the configuration of a saved query:

query {
runtime {
systemStreamDataSimpleQuery(rtId: "67e1a2b3c4d5e6f7a8b9c0d1") {
totalCount
items {
rtId
name
description
queryCkTypeId
columns
rtIds
from
to
limit
sorting {
attributePath
sortOrder
}
fieldFilter {
attributePath
operator
comparisonValue
}
}
}
}
}

Similarly for other types:

  • systemStreamDataAggregationQuery(rtId: "...")
  • systemStreamDataGroupingAggregationQuery(rtId: "...")
  • systemStreamDataDownsamplingQuery(rtId: "...")

Updating Persisted Queries

Update a saved query by providing its rtId and the fields to change:

mutation {
runtime {
systemStreamDataSimpleQuerys {
update(entities: [
{
rtId: "67e1a2b3c4d5e6f7a8b9c0d1"
name: "Updated voltage query"
columns: ["voltage", "power", "current"]
limit: 10000
}
]) {
rtId
name
columns
limit
}
}
}
}

The same pattern applies for the other query types using systemStreamDataAggregationQuerys, systemStreamDataGroupingAggregationQuerys, and systemStreamDataDownsamplingQuerys.


Persisted vs Transient Comparison

PersistedTransient
SetupCreate once, execute by rtIdSpecify all parameters per request
ReusabilityExecute the same query many timesOne-off queries
Dashboard integrationUse rtId in widget data source configurationNot suitable for widgets
Parameter flexibilityOverride from/to/limit at execution time via argFull control per request
ManagementStored as runtime entities, can be listed, updated, deletedNo storage
Use caseProduction dashboards, recurring reports, shared queriesAd-hoc exploration, one-time analysis