Google Health API 依赖于过滤表达式,以便在调用标准检索方法时限制返回的数据点。具体而言,过滤器可用于:
list端点:查询原始数据点。reconcile端点:用于查询已协调的流数据点。
本指南介绍了过滤功能的实现方式、语法和惯例,并针对每种记录类型提供了示例。
过滤条件惯例
Google Health API 按照 Google API 改进提案 (AIP-160) 标准实现过滤条件。
查询参数
过滤条件通过 filter 参数中的网址查询字符串传递。
由于过滤条件包含特殊字符(例如 <、>= 和引号),因此在 HTTP 请求中传输时必须进行网址编码。
例如,包含过滤条件 steps.interval.civil_start_time >= "2026-03-04T00:00:00" 的请求应编码为:
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints ?filter=steps.interval.civil_start_time%20%3E%3D%20%222026-03-04T00%3A00%3A00%22
命名格式
如果数据类型包含多个字词,资源路径和过滤器的标识符格式会有所不同:
- 端点路径:使用连字符(例如
/dataTypes/body-fat)。 - 过滤字符串:使用下划线(例如
body_fat)。
如果您在过滤条件标识符中使用连字符,API 会返回 400 Bad Request,并显示错误原因 INVALID_DATA_POINT_FILTER。
过滤条件类型和字段
您在过滤条件中使用的字段取决于您要查询的数据类型所对应的记录类型。下表介绍了每种记录类型支持的字段:
| 记录类型 | 说明 | 支持的过滤字段 |
|---|---|---|
| 间隔时间 | 在一段时间内记录的数据点(例如 steps、distance、calories)。 |
{dataType}.interval.start_time{dataType}.interval.civil_start_time
示例: steps.interval.civil_start_time
|
| 采样 | 瞬时观测或短期测量(例如 weight、body-fat、blood-glucose)。 |
{dataType}.sample_time.physical_time{dataType}.sample_time.civil_time
示例: body_fat.sample_time.physical_time
|
| 按天 | 每日指标和摘要(例如 daily-heart-rate-variability)。 |
{dataType}.date
示例: daily_heart_rate_variability.date
|
| 会话 | 具有特殊计时规则的延长用户会话。 |
锻炼: {dataType}.interval.civil_start_time睡眠: sleep.interval.end_time、sleep.interval.civil_end_time心电图: electrocardiogram.interval.start_time
示例: sleep.interval.civil_end_time
|
支持的运算符和格式规则
过滤表达式必须符合以下格式设置规则:
比较运算符
仅支持两个比较运算符:
| 运算符 | 说明 |
|---|---|
>= |
下限(含)。 |
< |
上限(不含)。 |
使用其他比较运算符(例如 >、<= 或 =)会返回一个包含 INVALID_DATA_POINT_FILTER_RESTRICTION_COMPARATOR 的 400 Bad Request。
逻辑运算符
| 运算符 | 支持 |
|---|---|
AND |
默认且唯一受支持的运算符。用于合并开始和结束边界。 |
OR |
不受支持。使用 OR 会返回 400 Bad Request,并显示错误原因 INVALID_DATA_POINT_FILTER_EXPRESSION_STRUCTURE(“过滤条件必须是限制的合取或序列。找到了:DISJUNCTION”)。 |
时间字面量
过滤表达式中的时间字面值必须采用以下格式:
| 时间类型 | 要求 | 示例 |
|---|---|---|
| 实际时间 | RFC 3339 格式,以 Z 或 UTC 偏移量结尾。以世界协调时间 (UTC) 表示现实世界中的事件。 |
正确:"2026-03-01T00:00:00Z"、"2026-03-01T00:00:00-08:00"错误: "2026-03-01" |
| 民用时间 | ISO 8601 格式:YYYY-MM-DD[THH:mm:ss]。表示用户时钟上的时间,与位置或时区偏移量无关。 |
正确:"2026-03-01"、"2026-03-01T08:30:00" |
过滤验证规则
过滤器遵循以下规则:
| 规则 | 说明 | 示例 |
|---|---|---|
| 不支持混合时间类型 | 请勿混用物理时间和民用时间边界。 | 无效:steps.interval.start_time >= "2026-03-01T00:00:00Z" AND steps.interval.civil_start_time < "2026-03-02"错误: INVALID_DATA_POINT_FILTER_MIXED_TIME_RESTRICTIONS(“过滤条件不能同时包含物理时间和民用时间范围”) |
| 无混合数据类型 | 在请求路径中使用属于相应数据类型的字段。 | 无效:包含过滤条件 distance.interval.start_time >= "..." 的路径 /users/.../dataTypes/steps/...错误: INVALID_DATA_POINT_FILTER_COLLECTION_MISMATCH(“过滤条件中的数据类型与父数据类型集合不匹配”) |
| 时间顺序逻辑 | 上限必须大于下限。 | 无效:steps.interval.start_time >= "2026-03-02T00:00:00Z" AND steps.interval.start_time < "2026-03-01T00:00:00Z"错误: INVALID_TIME_RANGE(“查询结束时间必须严格大于开始时间”) |
| 应用场景格式 | 使用与数据类型名称匹配的蛇形命名法。 | 无效:body-fat.sample_time.physical_time >= "..."错误: INVALID_DATA_POINT_FILTER(“过滤条件无效”) |
对于无效的过滤条件,API 会返回 HTTP 400 Bad Request。如需了解错误原因代码,请参阅 error.details[].metadata.detailedReasons。
必需的 OAuth 范围
如需使用过滤器查询数据点,获得授权的用户必须授予相应数据类型的相关 OAuth 范围。如果缺少必需的范围,API 会返回 403 Forbidden 状态和 MISSING_OAUTH_SCOPE。
下表将 OAuth 范围映射到它们授予读取权限的数据类型。下表以相对格式显示了各个范围(例如,.activity_and_fitness.readonly 表示 https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly):
| 必需的 OAuth 范围 | 数据类型 |
|---|---|
.activity_and_fitness.readonly |
active-energy-burned、active-minutes、active-zone-minutes、activity-level、altitude、calories-in-heart-rate-zone、daily-vo2-max、distance、exercise、floors、run-vo2-max、sedentary-period、steps、swim-lengths-data、time-in-heart-rate-zone、total-calories、vo2-max |
.ecg.readonly |
心电图 |
.health_metrics_and_measurements.readonly |
blood-glucose、body-fat、core-body-temperature、daily-heart-rate-variability、daily-heart-rate-zones、daily-oxygen-saturation、daily-respiratory-rate、daily-resting-heart-rate、daily-sleep-temperature-derivations、heart-rate、heart-rate-variability、height、oxygen-saturation、respiratory-rate-sleep-summary、skin-temperature-sensors、weight |
.irn.readonly |
irregular-rhythm-notification |
.nutrition.readonly |
food、food-measurement-unit、hydration-log、nutrition-log |
.sleep.readonly |
sleep |
如果您的客户端仅被授予对所请求数据类型的写入范围(例如 .activity_and_fitness.writeonly),您仍然可以查询您自己的客户端写入的数据点。在这种情况下,请求会隐式限制为 self-sources 数据源系列。如需了解详情和数据类型限制,请参阅按数据源系列过滤。
应用场景和示例
以下示例演示了如何针对常见场景构建过滤器:
按实际时间范围查询步数
在 2026-03-01T00:00:00Z(含)和 2026-03-02T00:00:00Z(不含)之间记录的查询步数:
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints ?filter=steps.interval.start_time >= "2026-03-01T00:00:00Z" AND steps.interval.start_time < "2026-03-02T00:00:00Z"
按民用时间范围查询步数
2026 年 3 月 4 日一整天的查询步数(相对于用户的本地时钟):
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints ?filter=steps.interval.civil_start_time >= "2026-03-04" AND steps.interval.civil_start_time < "2026-03-05"
按身体样本时间查询体脂
查询自 2026 年 3 月起记录的体脂测量数据(世界协调时间):
GET https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints ?filter=body_fat.sample_time.physical_time >= "2026-03-01T00:00:00Z"
按民用采样时间划分的查询权重
在特定本地时间之后记录的查询权重日志:
GET https://health.googleapis.com/v4/users/me/dataTypes/weight/dataPoints ?filter=weight.sample_time.civil_time >= "2026-03-01T08:00:00"
查询心率变异性每日摘要
查询在特定日期之前记录的心率变异性 (HRV) 日常摘要:
GET https://health.googleapis.com/v4/users/me/dataTypes/daily-heart-rate-variability/dataPoints ?filter=daily_heart_rate_variability.date < "2026-08-15"
按民用开始时间查询锻炼会话
查询用户本地时区中特定周内的锻炼会话:
GET https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints ?filter=exercise.interval.civil_start_time >= "2026-03-01" AND exercise.interval.civil_start_time < "2026-03-08"
按民用结束时间查询睡眠时段
按会话的结束时间查询睡眠记录:
GET https://health.googleapis.com/v4/users/me/dataTypes/sleep/dataPoints ?filter=sleep.interval.civil_end_time >= "2026-03-04T05:00:00" AND sleep.interval.civil_end_time < "2026-03-04T12:00:00"
按开始时间查询心电图
查询从某个实际 UTC 时间点开始的 ECG 记录。请注意,ECG 查询仅支持对 start_time 进行 >= 比较:
GET https://health.googleapis.com/v4/users/me/dataTypes/electrocardiogram/dataPoints ?filter=electrocardiogram.interval.start_time >= "2026-03-10T12:00:00Z"
按数据源系列过滤
数据源系列是数据源(例如智能手表、移动应用或手动输入的数据)的逻辑分组。借助该 API,您可以隔离或汇总来自特定类型来源(例如实体穿戴式设备、手动输入的数据或您自己的客户端写入的数据)的数据。
list、reconcile、rollUp 和 dailyRollUp 端点均支持 dataSourceFamily 参数。传递机制取决于端点:
| 端点 (HTTP 方法) | 机制 |
|---|---|
list (GET) |
将 dataSourceFamily 作为网址查询参数传递。 |
reconcile (GET) |
将 dataSourceFamily 作为网址查询参数传递。 |
rollUp (POST) |
将 dataSourceFamily 作为 JSON 请求正文中的字段进行传递。 |
dailyRollUp (POST) |
将 dataSourceFamily 作为 JSON 请求正文中的字段进行传递。 |
支持的数据源系列
下表介绍了支持的 dataSourceFamily 值:
| 选项 | 说明 |
|---|---|
users/me/dataSourceFamilies/all-sources |
默认值(授予读取范围时)。包括来自所有可用的第一方 (1P) 和第三方 (3P) 数据源的数据点。此选项会返回第三方应用数据(例如智能手表步数 + 第三方应用步数 + 手机步数 + 手动输入的步数)。 |
users/me/dataSourceFamilies/google-wearables |
包括 Google 和 Fitbit 追踪器设备(例如 Fitbit 穿戴式追踪器和 Pixel Watch)记录的数据。不包括手动记录的数据和手机估算的数据。如果您的集成需要由穿戴式硬件直接记录的原始传感器遥测数据,请使用此选项。 |
users/me/dataSourceFamilies/google-sources |
包括 Google 和 Fitbit 第一方来源。这包括实体追踪器设备记录、来自“健康数据共享”的数据,以及通过第一方应用(例如 Fitbit 应用或 Google 健身)手动记录的任何条目。 |
users/me/dataSourceFamilies/self-sources |
仅包含调用客户端通过 Google Health API 写入的数据(数据源通过 API 注册的数据点,且具有与调用者相同的 OAuth 客户端 ID)。 |
如果没有数据点与所请求的数据源系列匹配,则响应为空列表,而不是错误。
仅写入范围和自源
如果调用方仅被授予所请求数据类型的写入范围(例如 .activity_and_fitness.writeonly),则可以读取自己写入的数据,但只能读取这些数据。
- 未明确设置
dataSourceFamily参数或将dataSourceFamily设置为users/me/dataSourceFamilies/self-sources的请求会隐式限制为self-sources。 - 如果仅使用写入范围请求任何其他数据源系列(例如
all-sources、google-wearables或google-sources),则会因403 Forbidden(PERMISSION_DENIED) 错误而失败。
列表端点的数据类型限制
在 list 端点 (users.dataTypes.dataPoints.list) 上,sleep、food 和 food-measurement-unit 数据类型不支持按 dataSourceFamily 进行过滤:
- 针对
sleep、food或food-measurement-unit显式设置list上的dataSourceFamily会失败,并显示400 Bad Request(INVALID_ARGUMENT) 错误。 - 如果仅授予写入范围(其中调用者的范围隐含了对
self-sources的限制),则针对这些数据类型调用list会失败,并显示403 Forbidden(PERMISSION_DENIED) 错误。 - 如需按
dataSourceFamily过滤sleep数据点,请改用reconcile端点。
数据源系列示例
如需列出您自己的客户端为用户写入的原始数据点,请调用 list 端点并将 dataSourceFamily 查询参数设置为 users/me/dataSourceFamilies/self-sources。
例如,以下 GET 请求会列出调用客户端从 2026-03-01 开始写入的原始 body-fat 测量数据:
请求
GET https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints ?dataSourceFamily=users/me/dataSourceFamilies/self-sources &filter=body_fat.sample_time.physical_time >= "2026-03-01T00:00:00Z" Authorization: Bearer access-token Accept: application/json
响应
{
"dataPoints": [
{
"name": "users/123456789/dataTypes/body-fat/dataPoints/1234567890",
"dataSource": {
"recordingMethod": "UNKNOWN",
"application": {
"packageName": "",
"webClientId": "",
"googleWebClientId": "google-web-client-id"
},
"platform": "GOOGLE_WEB_API"
},
"bodyFat": {
"sampleTime": {
"physicalTime": "2026-03-10T10:00:00Z",
"utcOffset": "0s",
"civilTime": {
"date": {
"year": 2026,
"month": 3,
"day": 10
},
"time": {
"hours": 10
}
}
},
"percentage": 20
}
}
],
"nextPageToken": ""
}如需从特定数据源系列获取已协调的数据流,请使用 dataSourceFamily 查询参数调用 reconcile 端点。
例如,以下 GET 请求会提取 2026-03-03 之后一天的手环记录睡眠数据:
请求
GET https://health.googleapis.com/v4/users/me/dataTypes/sleep/dataPoints:reconcile ?dataSourceFamily=users/me/dataSourceFamilies/google-wearables &filter=sleep.interval.civil_end_time >= "2026-03-03" Authorization: Bearer access-token Accept: application/json
响应
{
"dataPoints": [
{
"name": "users/2515055256096816351/dataTypes/sleep/dataPoints/2724123844716220216",
"dataSource": {
"recordingMethod": "DERIVED",
"device": {
"displayName": "Charge 6"
},
"platform": "FITBIT"
},
"sleep": {
"interval": {
"startTime": "2026-03-03T20:57:30Z",
"startUtcOffset": "0s",
"endTime": "2026-03-04T04:41:30Z",
"endUtcOffset": "0s"
},
"type": "STAGES",
"stages": [
{
"startTime": "2026-03-03T20:57:30Z",
"startUtcOffset": "0s",
"endTime": "2026-03-03T20:59:30Z",
"endUtcOffset": "0s",
"type": "AWAKE",
"createTime": "2026-03-04T04:43:40.937183Z",
"updateTime": "2026-03-04T04:43:40.937183Z"
},
{
"startTime": "2026-03-04T04:07:30Z",
"startUtcOffset": "0s",
"endTime": "2026-03-04T04:41:30Z",
"endUtcOffset": "0s",
"type": "AWAKE",
"createTime": "2026-03-04T04:43:40.937183Z",
"updateTime": "2026-03-04T04:43:40.937183Z"
}
],
"metadata": {
"stagesStatus": "SUCCEEDED",
"processed": true,
"main": true
},
"summary": {
"minutesInSleepPeriod": "464",
"minutesAfterWakeUp": "0",
"minutesToFallAsleep": "0",
"minutesAsleep": "407",
"minutesAwake": "57",
"stagesSummary": [
{
"type": "AWAKE",
"minutes": "56",
"count": "12"
},
{
"type": "LIGHT",
"minutes": "198",
"count": "19"
},
{
"type": "DEEP",
"minutes": "114",
"count": "10"
},
{
"type": "REM",
"minutes": "94",
"count": "4"
}
]
},
"createTime": "2026-03-04T04:43:40.337983Z",
"updateTime": "2026-03-04T04:43:40.937183Z"
}
}
],
"nextPageToken": ""
}如需在特定窗口大小内汇总数据点,并限制为特定数据源系列,请调用 rollUp 端点,并在 JSON 请求正文中传递 dataSourceFamily 字段。
以下 POST 请求查询了以小时为间隔 (3600s) 统计的日内步行步数,这些步数完全来自穿戴式设备:
请求
POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:rollUp
Authorization: Bearer access-token
Accept: application/json
{
"range": {
"startTime": "2026-07-29T00:00:00Z",
"endTime": "2026-07-29T23:59:59Z"
},
"windowSize": "3600s",
"dataSourceFamily": "users/me/dataSourceFamilies/google-wearables"
}响应
{
"rollupDataPoints": [
{
"startTime": "2026-07-29T08:00:00Z",
"endTime": "2026-07-29T09:00:00Z",
"steps": {
"countSum": "1200"
}
},
{
"startTime": "2026-07-29T09:00:00Z",
"endTime": "2026-07-29T10:00:00Z",
"steps": {
"countSum": "3450"
}
}
]
}如需汇总特定来源系列中的每日数据点,请调用 dailyRollUp 端点,并在请求正文中传递 dataSourceFamily 字段。
例如,以下请求会计算用户步数的每日汇总数据,包括所有 Google 第一方来源和 Fitbit 来源(穿戴式设备 + 手动输入):
请求
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": 7,
"day": 28
},
"time": {
"hours": 0,
"minutes": 0,
"seconds": 0,
"nanos": 0
}
},
"end": {
"date": {
"year": 2026,
"month": 7,
"day": 30
},
"time": {
"hours": 0,
"minutes": 0,
"seconds": 0,
"nanos": 0
}
}
},
"windowSizeDays": 1,
"dataSourceFamily": "users/me/dataSourceFamilies/google-sources"
}响应
{
"rollupDataPoints": [
{
"civilStartTime": {
"date": {
"year": 2026,
"month": 7,
"day": 28
},
"time": {}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 7,
"day": 28
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59
}
},
"steps": {
"countSum": "8430"
}
},
{
"civilStartTime": {
"date": {
"year": 2026,
"month": 7,
"day": 29
},
"time": {}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 7,
"day": 29
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59
}
},
"steps": {
"countSum": "11245"
}
}
]
}