Aggregate records data from a stream

Required capabilities: StreamRecordsAcl:READ DataModelsAcl:READ

Aggregate data for records from the stream.

You can use an optional filter specification to limit the results.

The Records API supports three main groups of aggregates:

Metric aggregates: sum, min, max, count, etc.

Bucket aggregates (result records are aggregated into groups (buckets) — similar to the Data Model Instances groupBy concept): uniqueValues (group by property values), timeHistogram (group by date/time ranges), filters (group by filter criteria), etc.

Pipeline aggregates: movingFunction. Note: The pipeline aggregate applies to the results of another histogram aggregate. It applies to metrics (such as count, min, max, sum, etc.), not to the records in the parent aggregate buckets. This differs from sub-aggregates, which apply directly to records within each bucket.

Every aggregate request can contain multiple aggregate entries. Every bucket aggregate can contain multiple sub-aggregates (of any type), which are applied to records in each bucket of the parent aggregate.

Example:

Imagine there is paddle-tennis players game_statistics container with model:

{
  game_id: Long,
  game_time: Instant,
  player_name: String,
  points_scored: Int,
  ...
}

To get the following data:

for each day
    calculate average number of points scored by players in all games on that day
    and for each player
        calculate the total number of points scored by the player in all games they participated in on that day
        and find the max number of points scored by the player in all games they participated in on that day
and find the max number of points scored by players in all games they participated in during the entire search period.

Use aggregates like these (meta language):

timeHistogram(daily, game_time) // group by (form buckets) 1-day range based on `game_time` property values
    avg(points_scored)          // inside every day group calculate average value in `points_scored` property
    uniqueValues(player_name)   // inside every day group group by (form buckets) player names
        sum(points_scored)      // inside every player group which is inside every day group calculate the sum of points scored
        max(points_scored)      // inside every player group which is inside every day group find the maximum of points scored
max(points_scored)              // find the maximum number of points scored across all statistic records (without any grouping)

Or the same in Cognite Records Aggregates DSL (Json):

{
  "my_groups_by_1d_range": {
    "timeHistogram": {
      "calendarInterval": "1d",
      "property": [ "paddle", "game_statistics", "game_time" ],
      "aggregates": {
        "my_groups_by_player_name": {
          "uniqueValues": {
            "property": [ "paddle", "game_statistics", "player_name" ],
            "aggregates": {
              "my_player_daily_scores_sum": {
                "sum": { "property": [ "paddle", "game_statistics", "points_scored" ] }
              },
              "my_player_daily_scores_maximum": {
                "max": { "property": [ "paddle", "game_statistics", "points_scored" ] }
              }
            }
          }
        },
        "my_daily_scores_average": {
          "avg": { "property": [ "paddle", "game_statistics", "points_scored" ] }
        }
      }
    }
  },
  "my_scores_maximum_across_all_games": {
    "max": { "property": [ "paddle", "game_statistics", "points_scored" ] }
  }
}

and the response would be

{
  "my_groups_by_1d_range": {
    "timeHistogramBuckets": [
      {
        "count": 13
        "intervalStart": "2025-05-25T00:00:00Z",
        "aggregates": {
          "my_groups_by_player_name": {
            "uniqueValueBuckets": [
              {
                "count": 3
                "value": "Vasya Rogov",
                "aggregates": {
                  "my_player_daily_scores_sum": {
                    "sum": 57
                  },
                  "my_player_daily_scores_maximum": {
                    "max": 25
                  }
                }
              },
              {
                "count": 5
                "value": "Vinni Pooh",
                "aggregates": {
                  "my_player_daily_scores_sum": {
                    "sum": 53
                  },
                  "my_player_daily_scores_maximum": {
                    "max": 21
                  }
                }
              },
              ...
            ]
          },
          "my_daily_scores_average": {
            "avg": 33
          }
        }
      },
      {
        "count": 7
        "intervalStart": "2025-05-26T00:00:00Z",
        "aggregates": {
          "my_groups_by_player_name": {
            "uniqueValueBuckets": [
              {
                "count": 1
                "value": "Vasya Rogov",
                "aggregates": {
                  "my_player_daily_scores_sum": {
                    "sum": 24
                  },
                  "my_player_daily_scores_maximum": {
                    "max": 24
                  }
                }
              },
              {
                "count": 2
                "value": "Pyatochok",
                "aggregates": {
                  "my_player_daily_scores_sum": {
                    "sum": 42
                  },
                  "my_player_daily_scores_maximum": {
                    "max": 23
                  }
                }
              },
              ...
            ]
          },
          "my_daily_scores_average": {
            "avg": 22
          }
        }
      },
      ...
    ]
  },
  "my_scores_maximum_across_all_games": {
    "max": 42
  }
}
Securityoidc-token or oauth2-client-credentials or oauth2-open-industrial-data or oauth2-auth-code
Request
path Parameters
streamId
required
string [ 1 .. 100 ] characters ^[a-z]([a-z0-9_-]{0,98}[a-z0-9])?$

An identifier of the stream where the records are stored.

Example: test1
Request Body schema: application/json
required

Aggregation specification.

object (lastUpdatedTime)

Matches records with the last updated time within the provided range. This attribute is mandatory for immutable streams but it's optional for mutable streams. The maximum time interval that can be defined by the attribute is limited by the stream settings. If more data needs to be queried than allowed by the stream settings, it should be done with multiple requests. For example, if stream allows querying up to 1 month of data, but a quarterly report is needed, the solution is to make 3 requests, one for each month, and then aggregate the responses.

The range must include at least a left (gt or gte) bound. It is not allowed to specify two upper or lower bounds, e.g. gte and gt, in the same filter.

gte: Greater than or equal to. gt: Greater than. lte: Less than or equal to. lt: Less than.

Note: lastUpdatedTime is a CDF generated timestamp that marks the moment a record is stored in the API

The range bounds can be specified in two formats:

  • String: An ISO-8601 formatted date-time string (e.g., 2030-05-15T18:00:00.00Z).
  • Integer: The number of milliseconds since the Unix epoch (e.g., 1705341600000).
(boolFilter (and (object) or or (object) or not (object))) or (leafFilter (matchAll (object) or exists (object) or equals (object) or hasData (object) or prefix (object) or range (object) or in (object) or containsAll (object) or containsAny (object))) (filter)

A filter Domain Specific Language (DSL) used to create advanced filter queries.

Note: the max number of nodes in the filter tree is 100 and the max tree depth is 10.

required
object (aggregatesDictionary) [ 1 .. 5 ] properties unique

A dictionary of requested aggregates with client defined names/identifiers.

Example:

{
  "my_aggr_1": {
    "min": {"property": ["space1", "container1", "property1"]}
  },
  "my_aggr_2": {
    "uniqueValues": {
      "property": ["space1", "container2", "property1"],
      "aggregates": {
        "my_sub_aggr": {
          "avg": {"property": ["space2", "container1", "property3"]}
        }
      }
    }
  },
}

Max number of (sub-)aggregate trees on a level is 5, Max aggregate tree depth is 5. Max number of aggregates in the forest is 16.

Responses
200

Aggregated query results.

400

The response for a failed request.

post/streams/{streamId}/records/aggregate
Request samples
application/json
{
  • "lastUpdatedTime": {
    • "gt": 1705341600000,
    • "lt": "2030-05-15T18:00:00.00Z"
    },
  • "filter": {
    • "and": [
      ]
    },
  • "aggregates": {
    • "my_avg_aggregate1": {
      },
    • "my_terms_aggregate2": {
      }
    }
}
Response samples
application/json
{
  • "aggregates": {
    • "my_avg_aggregate1": {
      },
    • "my_terms_aggregate2": {
      }
    }
}