分组和聚合
Archie Core 通过其 GraphQL API 提供强大的分组和聚合功能。您可以按字段值对记录进行分组、计算聚合函数(COUNT、SUM、AVG、MIN、MAX、COUNT_DISTINCT)、使用 HAVING 条件过滤分组,并按聚合值对结果进行排序。
使用分组和聚合时,以下参数可用于任何列表查询:
| 参数 | 类型 | 描述 |
|---|---|---|
groupBy | [{TableName}GroupBy] | 用于分组结果的字段 |
aggregateBy | [{TableName}AggregateInput] | 要计算的聚合函数 |
having | [{TableName}HavingFilterInput] | 按聚合结果过滤分组 |
aggregateSort | [{TableName}AggregateSortInput] | 按聚合值对结果排序 |
这些参数可与 filter、first、skip 和 orderBy 等标准参数结合使用。
GroupBy
Section titled “GroupBy”groupBy 参数接受表示分组字段的枚举值数组。枚举值遵循以下模式:将 camelCase 字段名转换为大写。
命名约定:
| 列名(数据库) | 字段名(GraphQL) | GroupBy 枚举值 |
|---|---|---|
payment_method | paymentMethod | PAYMENTMETHOD |
created_at | createdAt | CREATEDAT |
status | status | STATUS |
category_id | categoryId | CATEGORYID |
示例:按活跃状态对学生分组
Section titled “示例:按活跃状态对学生分组”请求
query { students(groupBy: [ISACTIVE]) { items { isActive } count }}响应
{ "data": { "students": { "items": [ { "isActive": true }, { "isActive": false } ], "count": 2 } }}AggregateBy
Section titled “AggregateBy”aggregateBy 参数允许对分组(或未分组)数据计算聚合函数。每个聚合需要 function、可选的 field 和必需的 alias。
AggregateInput 结构
Section titled “AggregateInput 结构”input {TableName}AggregateInput { function: AggregateFunction! field: {TableName}AggregateField alias: String!}可用的聚合函数
Section titled “可用的聚合函数”| 函数 | 描述 | 是否需要 field? |
|---|---|---|
COUNT | 计数行数 | 否(省略时使用 COUNT(*)) |
SUM | 求和数值 | 是 |
AVG | 计算平均值 | 是 |
MIN | 查找最小值 | 是 |
MAX | 查找最大值 | 是 |
COUNT_DISTINCT | 计数不同值 | 是 |
field 枚举遵循与 GroupBy 相同的大写约定。
alias 是您选择用于命名结果的字符串。它作为 aggregates 响应对象中的键出现。
示例:按活跃状态分组的学生数量和平均年龄
Section titled “示例:按活跃状态分组的学生数量和平均年龄”请求
query { students( groupBy: [ISACTIVE] aggregateBy: [ { function: COUNT, alias: "totalStudents" } { function: AVG, field: AGE, alias: "avgAge" } ] ) { items { isActive } count aggregates }}响应
{ "data": { "students": { "items": [ { "isActive": true }, { "isActive": false } ], "count": 2, "aggregates": [ { "totalStudents": 5, "avgAge": 23.4 }, { "totalStudents": 2, "avgAge": 21.0 } ] } }}aggregates 数组中的每个条目对应于 items 中相同索引的分组。
Having
Section titled “Having”having 参数根据聚合结果过滤分组,相当于 SQL 的 HAVING 子句。它使用具有三个字段的专用输入类型。
HavingFilterInput 结构
Section titled “HavingFilterInput 结构”input {TableName}HavingFilterInput { alias: String! operator: HavingOperator! value: Float!}alias:必须与aggregateBy中定义的别名匹配。operator:比较运算符(见下表)。value:要比较的数值阈值。
可用的运算符
Section titled “可用的运算符”| 运算符 | SQL 等价 |
|---|---|
EQUALS | = |
NOT_EQUALS | != |
GREATER_THAN | > |
GREATER_THAN_OR_EQUAL | >= |
LESS_THAN | < |
LESS_THAN_OR_EQUAL | <= |
示例:学生超过 3 人的城市
Section titled “示例:学生超过 3 人的城市”请求
query { students( groupBy: [CITYID] aggregateBy: [ { function: COUNT, alias: "studentCount" } ] having: [ { alias: "studentCount", operator: GREATER_THAN, value: 3 } ] ) { items { cityId } count aggregates }}响应
{ "data": { "students": { "items": [ { "cityId": "e14638cb-6d72-4a36-b30f-9b763136a7bb" } ], "count": 1, "aggregates": [ { "studentCount": 5 } ] } }}仅返回满足聚合条件的分组。
AggregateSort
Section titled “AggregateSort”aggregateSort 参数按聚合值(而非普通字段)对分组结果进行排序。
AggregateSortInput 结构
Section titled “AggregateSortInput 结构”input {TableName}AggregateSortInput { alias: String! direction: SortDirection!}alias:必须与aggregateBy中定义的别名匹配。direction:ASC(升序)或DESC(降序)。
示例:按学生数量排序的前 3 个城市
Section titled “示例:按学生数量排序的前 3 个城市”请求
query { students( groupBy: [CITYID] aggregateBy: [ { function: COUNT, alias: "studentCount" } ] aggregateSort: [ { alias: "studentCount", direction: DESC } ] first: 3 ) { items { cityId } count aggregates }}响应
{ "data": { "students": { "items": [ { "cityId": "e14638cb-6d72-4a36-b30f-9b763136a7bb" }, { "cityId": "0174dc55-d494-4ebc-a0e9-13575461cad4" }, { "cityId": "a2b3c4d5-e6f7-8901-2345-678901234567" } ], "count": 3, "aggregates": [ { "studentCount": 5 }, { "studentCount": 3 }, { "studentCount": 2 } ] } }}组合所有功能
Section titled “组合所有功能”您可以在单个查询中组合 filter、groupBy、aggregateBy、having、aggregateSort 和 first 进行复杂分析。
示例:平均年龄超过 20 的活跃学生前 5 个城市,按平均年龄排序
Section titled “示例:平均年龄超过 20 的活跃学生前 5 个城市,按平均年龄排序”请求
query { students( filter: { isActive: { equals: true } } groupBy: [CITYID] aggregateBy: [ { function: COUNT, alias: "studentCount" } { function: AVG, field: AGE, alias: "avgAge" } { function: MAX, field: AGE, alias: "maxAge" } ] having: [ { alias: "avgAge", operator: GREATER_THAN, value: 20 } ] aggregateSort: [ { alias: "avgAge", direction: DESC } ] first: 5 ) { items { cityId } count aggregates }}响应
{ "data": { "students": { "items": [ { "cityId": "e14638cb-6d72-4a36-b30f-9b763136a7bb" }, { "cityId": "0174dc55-d494-4ebc-a0e9-13575461cad4" } ], "count": 2, "aggregates": [ { "studentCount": 3, "avgAge": 24.3, "maxAge": 28 }, { "studentCount": 2, "avgAge": 22.5, "maxAge": 25 } ] } }}此查询:
- 过滤仅活跃学生(
filter)。 - 按城市分组(
groupBy)。 - 计算每个分组的数量、平均年龄和最大年龄(
aggregateBy)。 - 保留仅平均年龄超过 20 的分组(
having)。 - 按平均年龄降序排序(
aggregateSort)。 - 限制为前 5 个分组(
first)。
使用聚合时,响应遵循带有额外 aggregates 字段的标准 Connection 类型:
| 字段 | 类型 | 描述 |
|---|---|---|
items | [{TableName}!]! | 分组记录(每组一个,包含分组字段值) |
count | Int! | 返回的分组数量 |
pageInfo | PageInfo! | 分页信息(hasNextPage、hasPreviousPage) |
aggregates | JSON | 对象数组,每个包含按别名索引的计算聚合值 |
aggregates 数组与 items 平行 — 索引 i 的聚合对应于 items 中索引 i 的分组。
- GroupBy 和 AggregateField 枚举值使用 camelCase 字段名的大写形式:
payment_method→paymentMethod→PAYMENTMETHOD。 - having 别名必须匹配
aggregateBy中定义的别名。如果不匹配,having 条件将被忽略。 - aggregateSort 别名必须匹配
aggregateBy中定义的别名。 - 无 field 的 COUNT 使用
COUNT(*),计算分组中所有行。 - 多个 having 条件可以组合 — 必须全部满足(AND 逻辑)。
- 多个 aggregateSort 条目按优先级顺序应用(第一个是主排序)。
- 标准分页参数(
first、skip、after、before)适用于分组结果。 - filter 参数在分组前应用(相当于 SQL WHERE),而 having 在分组后应用(相当于 SQL HAVING)。