跳转到内容

分组和聚合

Archie Core 通过其 GraphQL API 提供强大的分组和聚合功能。您可以按字段值对记录进行分组、计算聚合函数(COUNT、SUM、AVG、MIN、MAX、COUNT_DISTINCT)、使用 HAVING 条件过滤分组,并按聚合值对结果进行排序。

使用分组和聚合时,以下参数可用于任何列表查询:

参数类型描述
groupBy[{TableName}GroupBy]用于分组结果的字段
aggregateBy[{TableName}AggregateInput]要计算的聚合函数
having[{TableName}HavingFilterInput]按聚合结果过滤分组
aggregateSort[{TableName}AggregateSortInput]按聚合值对结果排序

这些参数可与 filterfirstskiporderBy 等标准参数结合使用。

groupBy 参数接受表示分组字段的枚举值数组。枚举值遵循以下模式:将 camelCase 字段名转换为大写。

命名约定:

列名(数据库)字段名(GraphQL)GroupBy 枚举值
payment_methodpaymentMethodPAYMENTMETHOD
created_atcreatedAtCREATEDAT
statusstatusSTATUS
category_idcategoryIdCATEGORYID

请求

query {
students(groupBy: [ISACTIVE]) {
items {
isActive
}
count
}
}

响应

{
"data": {
"students": {
"items": [
{ "isActive": true },
{ "isActive": false }
],
"count": 2
}
}
}

aggregateBy 参数允许对分组(或未分组)数据计算聚合函数。每个聚合需要 function、可选的 field 和必需的 alias

input {TableName}AggregateInput {
function: AggregateFunction!
field: {TableName}AggregateField
alias: String!
}
函数描述是否需要 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 参数根据聚合结果过滤分组,相当于 SQL 的 HAVING 子句。它使用具有三个字段的专用输入类型。

input {TableName}HavingFilterInput {
alias: String!
operator: HavingOperator!
value: Float!
}
  • alias:必须与 aggregateBy 中定义的别名匹配。
  • operator:比较运算符(见下表)。
  • value:要比较的数值阈值。
运算符SQL 等价
EQUALS=
NOT_EQUALS!=
GREATER_THAN>
GREATER_THAN_OR_EQUAL>=
LESS_THAN<
LESS_THAN_OR_EQUAL<=

请求

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 参数按聚合值(而非普通字段)对分组结果进行排序。

input {TableName}AggregateSortInput {
alias: String!
direction: SortDirection!
}
  • alias:必须与 aggregateBy 中定义的别名匹配。
  • directionASC(升序)或 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 }
]
}
}
}

您可以在单个查询中组合 filtergroupByaggregateByhavingaggregateSortfirst 进行复杂分析。

示例:平均年龄超过 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 }
]
}
}
}

此查询:

  1. 过滤仅活跃学生(filter)。
  2. 城市分组(groupBy)。
  3. 计算每个分组的数量、平均年龄和最大年龄(aggregateBy)。
  4. 保留仅平均年龄超过 20 的分组(having)。
  5. 平均年龄降序排序(aggregateSort)。
  6. 限制为前 5 个分组(first)。

使用聚合时,响应遵循带有额外 aggregates 字段的标准 Connection 类型:

字段类型描述
items[{TableName}!]!分组记录(每组一个,包含分组字段值)
countInt!返回的分组数量
pageInfoPageInfo!分页信息(hasNextPagehasPreviousPage
aggregatesJSON对象数组,每个包含按别名索引的计算聚合值

aggregates 数组与 items 平行 — 索引 i 的聚合对应于 items 中索引 i 的分组。

  • GroupBy 和 AggregateField 枚举值使用 camelCase 字段名的大写形式:payment_methodpaymentMethodPAYMENTMETHOD
  • having 别名必须匹配 aggregateBy 中定义的别名。如果不匹配,having 条件将被忽略。
  • aggregateSort 别名必须匹配 aggregateBy 中定义的别名。
  • 无 field 的 COUNT 使用 COUNT(*),计算分组中所有行。
  • 多个 having 条件可以组合 — 必须全部满足(AND 逻辑)。
  • 多个 aggregateSort 条目按优先级顺序应用(第一个是主排序)。
  • 标准分页参数firstskipafterbefore)适用于分组结果。
  • filter 参数在分组前应用(相当于 SQL WHERE),而 having 在分组后应用(相当于 SQL HAVING)。