web-dev-qa-db-ja.com

GraphQL:配列内のデータをフィルタリングする

簡単なことだと思いますが、GraphQLのドキュメントにもGraphcoolのドキュメントにも何も見つかりませんでした。

このスキーマを持つエンティティがあるとします(新しいGraphQLユーザー、スキーマ表現を間違えた場合は申し訳ありません)。

_Book {
  name: String!
  author: String!
  categories: [String!]
}
_

_"mystery"_カテゴリの一部であるすべての書籍に対してクエリを実行するにはどうすればよいですか? allBooks(filter: {})でフィルタリングできることはわかっていますが、_categories_in: ["mystery"]_と_categories_contains: "mystery"_ではうまくいきませんでした。

9
gCardinal

Categoryモデル

この状況についてもう少し考えてみると、Categoryモデルを作成するのは間違いありません。

たとえば、読者がお気に入りのカテゴリを後で購読できるようにしたいとします。または、既存のすべてのカテゴリのリストが必要な場合はどうなりますか?文字列リストを使用して、すべての書籍をクエリし、取得したすべてのカテゴリを何らかの方法で後処理する必要があります。文字列リストを使用するのではなく、モデルレベルでこれを処理する方がはるかに自然に感じられます。

代わりに、新しいCategoryモデルを作成し、CategoryBookの間に多対多の関係を追加できます。このような状況では、一意の列挙フィールドtagと文字列フィールドtextを追加します。 (一意の文字列フィールドtagだけでも適切でしょう。おそらく好みの問題です。)

この設定により、次のようなデータ要件を簡単に満たすことができます

どの書籍が特定のカテゴリに割り当てられていますか?

query {
  # query books by unique category tag
  Category(tag: MYSTERY) {
    books {
      id
    }
  }
  # query books by specific category text
  Category(filter: {
    text: "mystery"
  }) {
    books {
      id
    }
  }
}

特定のリストの少なくとも1つのカテゴリに割り当てられている書籍はどれですか?

query {
  allCategories(filter: {
    OR: [{
      tag: MYSTERY
    }, {
      tag: MAGIC
    }]
  }) {
    books {
      id
    }
  }
}

指定されたリストのすべてのカテゴリに割り当てられている本はどれですか?

query {
  allCategories(filter: {
    AND: [{
      tag: MYSTERY
    }, {
      tag: MAGIC
    }]
  }) {
    books {
      id
    }
  }
}

関連フィルター

上記のクエリは指定されたデータ要件を満たしていますが、書籍はレスポンスでCategoryによってグループ化されるため、クライアントのグループをフラット化する必要があります。

いわゆる関連フィルターを使用すると、その関連カテゴリーを定義した条件に基づいて本のみを取得するようにそれを変えることができます。

たとえば、クエリ指定されたリストの少なくとも1つのカテゴリに割り当てられた本の場合:

query {
  allBooks(filter: {
    OR: [{
      categories_some: {
        tag: MYSTERY
      },
      categories_some: {
        tag: MAGIC
      }
    }]
  }) {
    id
  }
}
10
marktani

ホストされたGraphQLサービスの使用に関心がある場合は、 scaphold.io がしばらくの間この機能を備えています。 APIのすべての接続フィールドにはWhereArgs引数が付いており、実際にデータを掘り下げることができるフィルターを公開しています。このようなスカラーのリストがある場合、WhereArgsにはcontainsnotContainsフィールドが含まれ、リスト内の値に基づいて結果をフィルタリングできます。これにより、このようなクエリを作成できます。

query MysteriousBooks($where:BookWhereArgs) {
  viewer {
    allBooks(where:$where) {
      edges { node { title, ... } }
    }
  }
}

# Variables
{
  "where": {
    "categories": {
      "contains": "mystery"
    }
  }
}

完全にするために、スカラーリストでフィルタリングする必要なしに、これを機能させるためにわずかなスキーマ再調整を行うこともできます。たとえば、Categoryをノード実装タイプにして、CategoryBookの間の接続を作成できます。 Bookには多くのカテゴリがありませんが、次のようなクエリを発行できます。

query MysteriousBooks($where: CategoryWhereArgs) {
  viewer {
    allCategories(where: $where) {
      books {
        edges { node { title, ... } }
      }
    }
  }
}

# Variables
{
  "where": { 
    "name": { 
      "eq": "mystery" 
    } 
  }
}

この方法でスキーマを構造化すると、アーカイブ内のすべての本をループ処理する必要なく、カテゴリ内の本をさらにフィルタリングできます。例えば。 「昨年に書かれたすべての謎の本」を効率的に求めることができます。

完全な開示:私はScapholdで働いていますが、切り替えない場合は難しい気持ちで試してみることをお勧めします。 GraphQLを試し、愛する人々に出会えるのを楽しみにしています。このタイプの動作を自分のサーバーに実装する方法に興味がある場合は、私に知らせてください。また、そこでサポートさせていただきます。

これが役に立てば幸いです!

0
mparis