コンテンツにスキップ

グループ化と集計

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引数は、グループ化するフィールドを表すenum値の配列を受け取ります。enum値は、camelCaseのフィールド名を大文字に変換したパターンに従います。

命名規則:

列名(DB)フィールド名(GraphQL)GroupBy enum値
payment_methodpaymentMethodPAYMENTMETHOD
created_atcreatedAtCREATEDAT
statusstatusSTATUS
category_idcategoryIdCATEGORYID

例:アクティブ状態で学生をグループ化

Section titled “例:アクティブ状態で学生をグループ化”

リクエスト

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のenumは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句に相当します。3つのフィールドを持つ専用の入力型を使用します。

input {TableName}HavingFilterInput {
alias: String!
operator: HavingOperator!
value: Float!
}
  • aliasaggregateByで定義されたaliasと一致する必要があります。
  • 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!
}
  • aliasaggregateByで定義されたaliasと一致する必要があります。
  • directionASC(昇順)またはDESC(降順)。

リクエスト

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 }
]
}
}
}

複雑な分析のために、1つのクエリで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}!]!グループ化されたレコード(グループごとに1つ、グループ化されたフィールド値を含む)
countInt!返されたグループ数
pageInfoPageInfo!ページネーション情報(hasNextPagehasPreviousPage
aggregatesJSON各オブジェクトがaliasでインデックス付けされた計算された集計値を含むオブジェクトの配列

aggregates配列はitemsと並行しています — インデックスiの集計はitemsのインデックスiのグループに対応します。

  • GroupByとAggregateFieldのenum値はcamelCaseフィールド名の大文字を使用します:payment_methodpaymentMethodPAYMENTMETHOD
  • havingのaliasaggregateByで定義されたaliasと一致する必要があります。一致しない場合、having条件は無視されます。
  • aggregateSortのaliasaggregateByで定義されたaliasと一致する必要があります。
  • fieldなしのCOUNTCOUNT(*)を使用し、グループ内のすべての行をカウントします。
  • 複数のhaving条件を組み合わせることができます — すべて満たす必要があります(AND論理)。
  • 複数のaggregateSortエントリは優先順位の順に適用されます(最初のエントリが主ソート)。
  • 標準のページネーション引数firstskipafterbefore)はグループ化された結果で動作します。
  • filter引数はグループ化の前に適用されます(SQL WHEREに相当)、havingはグループ化の後に適用されます(SQL HAVINGに相当)。