Datos agregados

La API de Google Health proporciona extremos de agregación dedicados que agrupan y resumen los registros de salud en períodos. En lugar de recuperar y sumar registros sin procesar individuales en el cliente, usa los extremos de agregación para calcular métricas (como totales, promedios, mínimos y máximos) en un flujo de datos conciliado:

  • El extremo rollUp agrega datos en intervalos de tiempo físicos en UTC con una duración de ventana configurable en segundos (windowSize).
  • El extremo dailyRollUp agrega datos de uno o más días calendario (windowSizeDays) con la hora civil relativa al reloj local del usuario.

Ambos extremos concilian automáticamente los datos superpuestos en los dispositivos conectados y excluyen los períodos en los que no se usa el wearable para los tipos de datos de wearables que admiten la detección de uso.

Compara los extremos de agregación

Elige el extremo de agregación que coincida con la forma en que tu aplicación agrupa y muestra las métricas de salud de series temporales:

Función Extremo rollUp Extremo dailyRollUp
Solicitud HTTP POST https://health.googleapis.com/v4/users/me/dataTypes/data-type/dataPoints:rollUp POST https://health.googleapis.com/v4/users/me/dataTypes/data-type/dataPoints:dailyRollUp
Representación del tiempo Tiempo físico en UTC (startTime y endTime en formato RFC 3339). Hora civil (start y end como objetos CivilDateTime).
Parámetro de ventana windowSize (duración de la cadena obligatoria en segundos, mínimo "1s"). windowSizeDays (cantidad de días opcional, expresada como número entero; el valor predeterminado es 1).
Objeto de respuesta RollupDataPoint DailyRollupDataPoint
Orden de las respuestas Orden cronológico inverso (la ventana más reciente primero) Orden cronológico inverso (la ventana más reciente primero)
Ideal para Gráficos intradía, histogramas por hora o minuto, y análisis de UTC de duración fija. Paneles diarios, tendencias de varios días y resúmenes que tienen en cuenta los viajes entre zonas horarias o el horario de verano.

Ambos extremos aplican límites máximos de rango de consulta según el tipo de datos:

  • Se aplica un rango de consulta máximo de 14 días a calories-in-heart-rate-zone, heart-rate, active-minutes y total-calories.
  • Se aplica un rango de consulta máximo de 90 días a todos los demás tipos de datos admitidos.

Para verificar qué tipos de datos admiten rollup y dailyRollup, consulta la referencia de los tipos de datos de la API de Google Health.

Agrega datos en intervalos de tiempo físicos

Usa el extremo rollUp para agregar datos durante un tiempo físico range (en UTC) agrupados por una duración de ventana en segundos (windowSize).

Cuando llames al extremo rollUp, proporciona un cuerpo de solicitud JSON que contenga el range cerrado-abierto (startTime inclusive, endTime exclusivo) y windowSize. Ten en cuenta los siguientes requisitos de windowSize:

  • La duración de windowSize debe ser de al menos 1 segundo ("1s"). La API rechaza las duraciones de menos de un segundo, cero o negativas con un error 400 Bad Request (INVALID_ROLLUP_WINDOW).
  • Para evitar una distribución desigual de los datos agregados en los subbuckets, elige un windowSize que sea igual o mayor que la resolución de almacenamiento subyacente del tipo de datos (como "60s" para intervalos de pasos de 1 minuto). Para obtener más detalles, consulta Período de resumen y resolución de almacenamiento.

Por ejemplo, la siguiente solicitud acumula los recuentos de pasos en intervalos de 1 minuto (60s):

Solicitud

POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:rollUp
Authorization: Bearer access-token
Accept: application/json

{
  "range": {
    "startTime": "2026-02-17T17:00:00Z",
    "endTime": "2026-02-17T17:59:59Z"
  },
  "windowSize": "60s"
}

Respuesta

{
  "rollupDataPoints": [
    {
      "startTime": "2026-02-17T17:55:00Z",
      "endTime": "2026-02-17T17:56:00Z",
      "steps": {
        "countSum": "72"
      }
    },
    {
      "startTime": "2026-02-17T17:54:00Z",
      "endTime": "2026-02-17T17:55:00Z",
      "steps": {
        "countSum": "85"
      }
    },
...
  ]
}

Agrega datos de varios días calendario

Usa el extremo dailyRollUp para agregar datos de un solo día calendario o de varios días (windowSizeDays). Proporciona la hora civil de cierre y apertura range (start y end) en el cuerpo de la solicitud. Según el tipo de datos, el extremo devuelve valores agregados, como la suma o el promedio de cada período civil.

Debido a que dailyRollUp opera en el tiempo civil con las compensaciones de UTC registradas con cada dato, concilia automáticamente las duraciones variables de los días causadas por las transiciones del horario de verano o los viajes por zonas horarias.

Por ejemplo, la siguiente solicitud agrega recuentos de pasos durante un solo día civil (windowSizeDays: 1):

Solicitud

POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:dailyRollUp
Authorization: Bearer access-token
Accept: application/json

{
  "range": {
    "start": {
      "date": {
        "year": 2026,
        "month": 2,
        "day": 26
      },
      "time": {
        "hours": 0,
        "minutes": 0,
        "seconds": 0,
        "nanos": 0
      }
    },
    "end": {
      "date": {
        "year": 2026,
        "month": 2,
        "day": 26
      },
      "time": {
        "hours": 23,
        "minutes": 59,
        "seconds": 59,
        "nanos": 0
      }
    }
  },
  "windowSizeDays": 1
}

Respuesta

{
  "rollupDataPoints": [
    {
      "civilStartTime": {
        "date": {
          "year": 2026,
          "month": 2,
          "day": 26
        },
        "time": {}
      },
      "civilEndTime": {
        "date": {
          "year": 2026,
          "month": 2,
          "day": 26
        },
        "time": {
          "hours": 23,
          "minutes": 59,
          "seconds": 59
        }
      },
      "steps": {
        "countSum": "3822"
      }
    }
  ]
}

Agrega por familia de fuentes de datos

Tanto rollUp como dailyRollUp aceptan un campo dataSourceFamily opcional en el cuerpo de la solicitud JSON para restringir la agregación a grupos de fuentes específicos:

  • La opción users/me/dataSourceFamilies/all-sources (predeterminada) agrega los datos conciliados en todas las fuentes propias y de terceros registradas.
  • La opción users/me/dataSourceFamilies/google-wearables agrega los datos registrados por los dispositivos de seguimiento wearable de Google y Fitbit, y excluye los datos registrados manualmente y los estimados por el teléfono.
  • La opción users/me/dataSourceFamilies/google-sources agrega datos de fuentes propias de Google y Fitbit, incluidos los monitores de actividad wearable, Health Connect y las entradas manuales en apps propias.

Para conocer todos los requisitos de los parámetros y ver ejemplos de solicitudes y respuestas, consulta Filtra por familia de fuentes de datos en la guía Filtrar datos.

Período de resumen y resolución de almacenamiento

Aunque el extremo rollUp acepta cualquier windowSize de 1 segundo ("1s") o más, los diferentes tipos de datos registran y conservan las mediciones con diferentes tasas de muestreo o duraciones de intervalos en el almacenamiento subyacente. Por ejemplo, las métricas de actividad física de wearables, como steps, distance, active-minutes y active-energy-burned, suelen registrarse en intervalos de 1 minuto (60s).

En la siguiente tabla, se enumeran las resoluciones de almacenamiento subyacentes y los valores mínimos recomendados de windowSize para los tipos de datos comunes:

Resolución de almacenamiento Mínimo recomendado: windowSize Tipos de datos
1 segundo (1s) "1s" heart-rate
1 minuto (60s) "60s" active-energy-burned, active-minutes, active-zone-minutes, altitude, calories-in-heart-rate-zone, distance, floors, steps, time-in-heart-rate-zone, total-calories

Cuando se agregan tipos de datos de intervalo, el extremo rollUp coloca cada dato registrado en el bucket que contiene el startTime del dato. La API no divide, interpola ni distribuye datos de intervalos en buckets de subintervalos.

Si especificas un windowSize que es menor que el intervalo de almacenamiento de datos subyacente (por ejemplo, si solicitas una ventana de 10 segundos para steps almacenado en intervalos de 1 minuto), ocurrirá lo siguiente:

  1. El primer subintervalo que coincide con el startTime del intervalo (por ejemplo, de 10:00:00 a 10:00:10) recibe el recuento acumulado de todo el minuto (por ejemplo, los 100 pasos registrados para ese minuto).
  2. Los subbuckets restantes dentro de ese mismo minuto (de 10:00:10 a 10:00:20, de 10:00:20 a 10:00:30, etcétera) no reciben datos, ya que no comienza ningún intervalo dentro de esas ventanas.

Esto produce datos con picos en los que el valor de todo el intervalo se concentra en la primera subventana, como se muestra en la Figura 1.

Agrupación de resúmenes de subintervalos en comparación con la resolución de almacenamiento
Figura 1: Agrupación de resúmenes de subintervalos en la que se asigna un intervalo de 1 minuto al primer subintervalo de 10 segundos por startTime

Para obtener agregaciones significativas y distribuidas de manera uniforme, siempre establece windowSize en una duración igual o mayor que la resolución de almacenamiento subyacente del tipo de datos de destino (por ejemplo, "60s" o más para steps). Para conocer la resolución de almacenamiento y la ventana de resumen mínima recomendada de cada tipo de datos, consulta la referencia de los tipos de datos de la API de Google Health.

Agrupación en buckets cuando el rango no es un múltiplo del tamaño de la ventana

Si el intervalo solicitado no es un múltiplo exacto de windowSize (o windowSizeDays), el intervalo cronológico final se trunca en el extremo superior del intervalo y abarca una duración más corta que el tamaño de la ventana. La API acepta tu solicitud sin modificaciones y no realiza redondeos, cambios de hora ni interpolación de datos.

Para abarcar todo el rango solicitado, la API usa la división de límite superior para calcular la cantidad total de ventanas de agregación:

Number of windows = ceiling(Range duration / Window size)

Cada bucket comienza de forma secuencial desde el principio de tu rango. Si agregas otra ventana de tamaño completo que se extiende más allá de la hora de finalización solicitada, la ventana final se trunca (se fija) en la hora de finalización del intervalo.

Cómo funciona la asignación de buckets

Cuando solicitas resúmenes con rangos no divisibles, la API aplica las siguientes reglas:

  • La asignación de buckets comienza al principio del rango solicitado (range.startTime o range.start) y avanza según el tamaño de la ventana (windowSize o windowSizeDays).
  • El bucket cronológico final se limita al final del rango solicitado (range.endTime o range.end), lo que abarca una duración más corta que el tamaño de la ventana solicitada.
  • Los objetos RollupDataPoint o DailyRollupDataPoint que se devuelven incluyen sus propias marcas de tiempo de inicio y finalización explícitas, que puedes usar para inspeccionar la duración real del bucket truncado.
  • Debido a que la API devuelve datos de resumen en orden cronológico inverso (primero los más recientes), el bucket cronológico final (el bucket truncado) aparece como el primer elemento (index 0) en la lista que se muestra.

En la figura 2, se ilustra cómo la API agrupa un rango no divisible hacia adelante desde range.startTime, fija el bucket final en range.endTime y devuelve los buckets resultantes en orden cronológico inverso.

Agrupación de resúmenes, truncamiento y orden de las respuestas
Figura 2: Agrupación de resúmenes, truncamiento de fin de rango y orden de respuesta cronológico inverso

Ejemplo de un rango de 12 minutos con una ventana de 5 minutos

Supongamos que un cliente solicita un resumen en un intervalo de 12 minutos con un windowSize de 5 minutos ("300s"):

  • El valor de range.startTime es 10:00:00Z.
  • El valor de range.endTime es 10:12:00Z, para una duración total de 12 minutos.
  • El valor de windowSize es "300s" (5 minutos).

Como 12 minutos no es un múltiplo exacto de 5 minutos (12 = 5 * 2 + 2), la API calcula la cantidad de ventanas como ceiling(12 / 5) = 3. Esto produce tres buckets cronológicos:

Bucket Intervalo Duración Estado del período
Bucket 1 [10:00:00Z, 10:05:00Z) 5 minutos Ventana completa
Bucket 2 [10:05:00Z, 10:10:00Z) 5 minutos Ventana completa
Bucket 3 [10:10:00Z, 10:12:00Z) 2 minutos Se truncó en range.endTime

Impacto en los valores agregados

Debido a que la ventana cronológica final tiene una duración más corta, las métricas aditivas (como la suma o el recuento de pasos) son más bajas en el bucket truncado debido al período más corto.

Si un usuario camina a un ritmo constante de 100 pasos por minuto durante todo este intervalo de 12 minutos, los buckets contienen los siguientes totales:

  • El bucket 1 (de 10:00:00Z a 10:05:00Z) registra 500 pasos (5 minutos a 100 pasos por minuto).
  • El intervalo 2 (de 10:05:00Z a 10:10:00Z) registra 500 pasos (5 minutos a 100 pasos por minuto).
  • El intervalo 3 (de 10:10:00Z a 10:12:00Z) registra 200 pasos (2 minutos a 100 pasos por minuto).

El recuento de pasos más bajo de 200 pasos en el bucket 3 se debe a la duración de 2 minutos de la ventana truncada, no a una disminución en la actividad del usuario. Cuando traces o analices estos datos, normaliza los recuentos con la duración explícita de cada bucket para evitar presentar una caída engañosa en la actividad del usuario.

En la Figura 3, se comparan los totales de pasos aditivos sin procesar (countSum) con las tasas normalizadas por duración en los tres buckets.

Comparación de los totales de pasos sin procesar de los buckets y las tasas de pasos normalizadas
Figura 3: Totales aditivos sin procesar en comparación con las tasas normalizadas por duración para un bucket de resumen truncado

Ejemplo de respuesta de la API que muestra el orden

Debido a que la API devuelve los resultados en orden cronológico inverso, el bucket truncado aparece como el primer elemento de la lista que se muestra:

{
  "rollupDataPoints": [
    {
      "startTime": "2026-08-20T10:10:00Z",
      "endTime": "2026-08-20T10:12:00Z",
      "steps": {
        "countSum": "200"
      }
    },
    {
      "startTime": "2026-08-20T10:05:00Z",
      "endTime": "2026-08-20T10:10:00Z",
      "steps": {
        "countSum": "500"
      }
    },
    {
      "startTime": "2026-08-20T10:00:00Z",
      "endTime": "2026-08-20T10:05:00Z",
      "steps": {
        "countSum": "500"
      }
    }
  ]
}