Aggregate data

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(client: HealthConnectClient): Double? {
    val request = AggregateRequest(
        metrics = setOf(Distance.DISTANCE_TOTAL),
        timeRangeFilter = TimeRangeFilter.between(START_TIME, END_TIME)
    )
    val response = client.aggregate(request)
    // The result may be null if no data is available to aggregate.
    return response.getMetric(Distance.DISTANCE_TOTAL)
}

Basic aggregations: statistical

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

Here’s an example of statistical aggregation:

suspend fun aggregateHROverTime(client: HealthConnectClient): Long? {
    val aggregate = client.aggregate(
        AggregateRequest(
            setOf(HeartRateSeries.BPM_MAX),
            timeRangeFilter = TimeRangeFilter.between(START_TIME, END_TIME),
            dataOriginFilter = listOf(
                DataOrigin("androidx.health.connect.client.sample")
            )
        )
    )
    // The result may be null if no data is available to aggregate. 
    return aggregate.getMetric(HeartRateSeries.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 aggregateIntoMonths(healthConnectClient: HealthConnectClient) {
    val aggregateGroupByPeriodRequest = AggregateGroupByPeriodRequest(
        metrics = setOf(Steps.TOTAL),
        timeRangeFilter = TimeRangeFilter.between(START_TIME, END_TIME),
        timeRangeSlicer = Period.ofMonths(1)
    )
    val response = healthConnectClient.aggregateGroupByPeriod(
        aggregateGroupByPeriodRequest
    )
    response.forEach { period ->
        val totalSteps = period.result.getMetric(Steps.TOTAL) ?: 0L
    }
}

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