Aggregate data

Stay organized with collections Save and categorize content based on your preferences.

Aggregating data in Health Connect can include basic aggregations or aggregating data into buckets. The following workflows show you how to do both.

Basic aggregations: cumulative

The following example shows you how to aggregate data for a data type.

suspend fun aggregateDistance(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response =
        healthConnectClient.aggregate(
            AggregateRequest(
                metrics = setOf(DistanceRecord.DISTANCE_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
    // The result may be null if no data is available in the time range.
    val distanceTotalInMeters = response[DistanceRecord.DISTANCE_TOTAL]?.inMeters ?: 0L
}

Basic aggregations: statistical

Statistical aggregation will compute the minimum, maximum, or average values.

Here’s an example of statistical aggregation:

suspend fun aggregateHeartRate(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response =
        healthConnectClient.aggregate(
            AggregateRequest(
                setOf(HeartRateRecord.BPM_MAX, HeartRateRecord.BPM_MIN),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
    // The result may be null if no data is available in the time range.
    val minimumHeartRate = response[HeartRateRecord.BPM_MIN]
    val maximumHeartRate = response[HeartRateRecord.BPM_MAX]
}

Buckets

Health Connect allows you to aggregate into buckets. There are two types of buckets that can be used:

  • Duration - where each bucket is of a fixed length in time, for example a minute or an hour.
  • Period - where each bucket is of a conceptual length in time, for a example a week or a month.

Health Connect returns a list of buckets. Note that this list is sparse, so, where a bucket would contain no data, it is not present in the list.

The following shows an example of aggregating steps into monthly buckets:

suspend fun aggregateStepsIntoMonths(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response =
        healthConnectClient.aggregateGroupByPeriod(
            AggregateGroupByPeriodRequest(
                metrics = setOf(StepsRecord.COUNT_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
                timeRangeSlicer = Period.ofMonths(1)
            )
        )
    for (monthlyResult in response) {
        // The result may be null if no data is available in the time range.
        val totalSteps = monthlyResult.result[StepsRecord.COUNT_TOTAL]
    }
}

To aggregate by Duration, the approach follows the same pattern as previously, but instead uses the aggregateGroupByDuration(request: AggregateGroupByDurationRequest) method.