[Keystone] GraphQL クエリ - フィルター

GraphQL クエリ - フィルター

Keystone は、システム内のデータをクエリするための強力な GraphQL API を提供しています。この API の中心には、クエリフィルターがあります。このガイドでは、フィルターを使用して必要なデータを取得する方法を説明します。

スカラーフィルター

システム内のすべてのタスクを検索したい場合は、クエリ tasks() を使用できます。

{
  tasks {
    id
    label
  }
}

一般的に、すべてのタスクを一度に取得するのではなく、特定の条件に一致するタスクのセットを検索したい場合があります。Keystone では、tasks() クエリに where 引数を渡すことで、これを実行できます。
ラベルが “Hello” であるすべてのタスクを検索したい場合は、次のように書くことができます。

{
  tasks(where: { label: { equals: "Hello" } }) {
    id
    label
  }
}

Keystone は、さまざまな種類のフィルターを提供しています。ラベルが “Hello” でないすべてのタスクを検索したい場合は、次のように書くことができます。

{
  tasks(where: { label: { not: { equals: "Hello" } } }) {
    id
    label
  }
}

text() フィールドタイプは、フィールド内のサブストリングを検索することもサポートしています。

{
  tasks(where: { label: { contains: "He" } }) {
    id
    label
  }
}

異なるフィールドタイプは、異なるフィルターをサポートしています。たとえば、finishBy: timestamp() フィールドでは、特定の時点以降に期限が設定されたタスクでフィルタリングすることができます。

{
  tasks(where: { finishBy: { gt: "2022-01-01T00:00:00.000Z" } }) {
    id
    label
  }
}

各フィールドタイプが提供する異なるフィルターの完全なリストについては、Query Filter API を確認してください。
より複雑なクエリには、複数のフィルターを組み合わせて、すべての条件に一致するアイテムのみを返すことができます。

{
  tasks(where: {
    label: { contains: "He" },
    finishBy: { gt: "2022-01-01T00:00:00.000Z" }
  }) {
    id
    label
  }
}

複合フィルター

より高度なクエリでは、異なるフィルターを明示的に組み合わせる必要がある場合があります。

AND

AND 演算子は、サブフィルターのリストを受け取り、これらの条件にすべて一致するアイテムのみを返します。

{
  tasks(where: { AND: [
    { label: { contains: "H" } },
    { label: { contains: "ll" } }
  ] }) {
    id
    label
  }
}

OR

OR 演算子は、サブフィルターのリストを受け取り、これらの条件のうち少なくとも1つに一致するアイテムのみを返します。

{
  tasks(where: { OR: [
    { label: { contains: "H" } },
    { label: { contains: "ll" } }
  ] }) {
    id
    label
  }
}

NOT

NOT 演算子は、サブフィルターのリストを受け取り、その条件に一致しないアイテムのみを返します。通常、NOT に渡すのは単一のフィルターであり、リストを渡す場合は、それらがANDで結合されます。

{
  tasks(where: { NOT: {
    label: { contains: "H" }
  } }) {
    id
    label
  }
}

リレーションシップフィルター

スカラーフィールドでフィルタリングすることに加えて、リレーションシップフィールドでフィルタリングすることもできます。利用可能なリレーションシップフィルターは、関係の向こう側に存在できるアイテムの数に依存します。つまり、フィールドで many: true または many: false が設定されているかどうかによります。

To-One (1対1)

リレーションシップフィールドで many: false が設定されている場合、関連するリストのフィールドを使用して、where フィルターに基づいてアイテムを検索できます。
例えば、タスクがユーザー「Alice」に割り当てられているすべてのタスクを検索するには、以下のクエリを実行できます。

{
  tasks(where: { assignedTo: { name: { equals: "Alice" } } }) {
    id
    label
  }
}

割り当てられたユーザーがいないタスクを検索するには、次のクエリを実行できます。

{
  tasks(where: { assignedTo: null }) {
    id
    label
  }
}

逆に、ユーザーが割り当てられているタスクを取得したい場合、NOT 演算子を使用して上記のクエリを反転させることができます。

{
  tasks(where: { NOT: { assignedTo: null } }) {
    id
    label
  }
}

To-Many (1対多)

関連するフィールドに many: true が設定されている場合、関連するアイテムのいくつか、なし、またはすべてが条件に一致するかどうかに基づいてアイテムを検索できます。 条件自体は、関連リストのフィールドを使用した where フィルター、またはすべての関連アイテムに一致する必要があることを示す空のオブジェクト({})を使用できます。

Some

some フィルターは、関連するアイテムのうち、少なくとも1つが条件に一致する場合に true を返します。
例えば、「shopping」を含むラベルを持つタスクが 1 つ以上ある人を見つけるには、次のクエリを実行できます。

{
  people(where: { tasks: { some: { label: { contains: "shopping" } } } }) {
    id
    name
  }
}

どのタスクでも構わない場合、空のオブジェクトを渡すことができます。これは、タスクに条件が適用されないことを示し、すべてのタスクがマッチすることを意味します。例えば、次のクエリを実行できます。

{
  people(where: { tasks: { some: {} } }) {
    id
    name
  }
}
None

none フィルタは、関連するアイテムが条件に一致しない場合に true を返します。
例えば、私たちが割り当てる緊急のタスクがある場合、未完了で高優先度のタスクがない人物を検索するために、次のようなクエリを実行できます。

{
  people(where: { tasks: { none: { priority: { equals: high }, isComplete: { equals: false } } } }) {
    id
    name
  }
}

以下のように、関連付けられたタスクが一つもない人物を検索することができます。ここでは、空のオブジェクトを none フィルターに渡しています。これは、条件がタスクに適用されないことを示し、全てのタスクがマッチすることを意味します。

{
  people(where: { tasks: { none: {} } }) {
    id
    name
  }
}
Every

every フィルターは、関連するアイテム全てが条件に合致する場合にtrueを返します。
例えば、担当タスクをすべて完了した人を検索する場合、次のように記述できます。

{
  people(where: { tasks: { every: { isComplete: { equals: true } } } }) {
    id
    name
  }
}

注意点として、結果には何もタスクが割り当てられていない人も含まれることになります。実際に少なくとも1つのタスクが割り当てられた人かつそのタスクが完了している人のみを取得したい場合は、some フィルターを追加することができます。

{
  people(where: { tasks: { every: { isComplete: { equals: true } }, some: {} } }) {
    id
    name
  }
}

他の “to-many” 関連フィルターと同様に、every フィルターも空のオブジェクトを受け入れますが、関連する項目に対してフィルタを適用しないことを示すだけで、効果はありません。関連する項目のプロパティや存在しない場合に関係なく、常に true と評価されます。したがって、次のようなクエリは、次のようになります。

{
  people(where: { tasks: { every: {} } }) {
    id
    name
  }
}

以下のように書き換えることができます。

{
  people {
    id
    name
  }
}

関連するアイテムをフィルタリングする方法

上記の関係性の例では、関連するアイテムに基づいてアイテムをフィルタリングしていますが、関連するアイテム自体の情報を読み込むことはありませんでした。GraphQL は、相互に接続されたアイテムのグラフを横断してデータを取得するクエリを書くことができます。Keystone では、関係性がこれらのアイテムの間のリンクを形成します。これらのリンクをトラバースするクエリは、トップレベルの「リスト」フィールド (これらの例ではタスクと人物) と、関連するアイテム自体に関するデータを選択する際にフィルタを適用します。
これは例を使って説明するとわかりやすいので、前述の例を拡張してみましょう。高優先度で未完了のタスクを持たない人を見つけたいが、彼らがまだリストに持っているすべての未完了のタスクを見たいとします。以下のように書くことができます。

{
  # Only return people who have no high-priority, incomplete tasks
  people(where: {
    tasks: {
      none: {
        priority: { equals: high },
        isComplete: { equals: false }
      }
    }
  }) {
    id
    name
    # For each person, get tasks that are not complete
    tasks(where: {
      isComplete: { equals: false }
    }) {
      id
      label
    }
  }
}

Keystone の GraphQL API で可能なことを探索する良い方法は、開発中の GraphQL エンドポイント (つまり、http:// localhost:3000 / api / graphqlで) に利用可能な GraphQL Playground を使用することです。