web-dev-qa-db-fra.com

GraphQL: Filtrer les données dans un tableau

Je suis sûr que c'est une chose simple à faire, mais je n'ai rien trouvé dans la documentation de GraphQL ni dans celle de Graphcool.

Dites que j'ai une entité avec ce schéma (nouvel utilisateur GraphQL, désolé si je me trompe dans la représentation du schéma):

Book {
  name: String!
  author: String!
  categories: [String!]
}

Comment ferais-je une requête pour tous les livres faisant partie de la catégorie "mystery"? Je sais que je peux filtrer avec allBooks(filter: {}), mais categories_in: ["mystery"] et categories_contains: "mystery" n'ont pas fait l'affaire.

8
gCardinal

modèle Category

En réfléchissant un peu plus à cette situation, créer un modèle Category est définitivement la voie à suivre.

Par exemple, imaginons que vous souhaitiez permettre aux lecteurs de s'abonner ultérieurement à leurs catégories préférées. Ou, si vous voulez une liste de toutes les catégories existantes? À l'aide de listes de chaînes, vous devez interroger tous les livres et post-traiter en quelque sorte toutes les catégories obtenues. Gérer cela au niveau du modèle plutôt que d'utiliser des listes de chaînes semble beaucoup plus naturel.

Au lieu de cela, vous pouvez créer un nouveau modèle Category et ajouter une relation plusieurs à plusieurs entre Category et Book. Dans de telles situations, j'aime bien ajouter un champ d'enum unique tag et un champ de chaîne text. (Un champ de chaîne unique tag seul conviendrait également, probablement une question de goût.)

Avec cette configuration, vous pouvez facilement répondre aux exigences de données telles que 

Quels livres sont affectés à une catégorie donnée?

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

Quels livres sont affectés à au moins une catégorie d'une liste donnée?

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

Quels livres sont affectés à toutes les catégories d'une liste donnée?

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

Filtres associés

Même si les requêtes ci-dessus répondent aux exigences de données spécifiées, les livres sont regroupés par Category dans la réponse, ce qui signifie que nous devrions aplanir les groupes sur le client.

Avec ce qu'on appelle les filtres associés, nous pouvons inverser ce problème en obtenant uniquement des livres en fonction de conditions définies par ses catégories associées.

Par exemple, pour interroger les livres affectés à au moins une catégorie d’une liste donnée :

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

Si vous souhaitez utiliser un service GraphQL hébergé, scaphold.io dispose de cette fonctionnalité depuis un certain temps. Tous les champs de connexion de votre API sont livrés avec un argument WhereArgs qui expose des filtres qui vous permettent de vraiment creuser dans vos données. Lorsque vous avez une liste de scalaires comme celle-ci, les objets WhereArgs incluent un champ contains & notContains qui vous permet de filtrer les résultats en fonction des valeurs de votre liste. Cela vous permet de faire une requête comme celle-ci.

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

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

Juste pour être complet, vous pourriez aussi faire un léger réajustement de schéma pour que cela fonctionne sans avoir à filtrer sur une liste scalaire. Par exemple, vous pouvez définir Category comme type de nœud d'implémentation, puis créer une connexion entre Category et Book. Bien qu'une Book n'aura probablement pas beaucoup de catégories, cela vous permettrait d'émettre une requête comme celle-ci:

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

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

Si vous structurez votre schéma de cette façon, vous pourrez également filtrer davantage les livres de la catégorie sans avoir à parcourir en boucle tous les livres de vos archives. PAR EXEMPLE. vous pouvez demander efficacement «tous les livres de mystère écrits au cours de la dernière année».

Divulgation complète: je travaille chez Scaphold et même si j'aimerais beaucoup que vous essayiez sans détours, si vous ne passez pas à autre chose. Je suis excité de voir des gens essayer et aimer GraphQL. Si vous êtes curieux de savoir comment mettre en œuvre ce type de comportement sur votre propre serveur, faites-le-moi savoir et je serais ravi de pouvoir vous aider également!

J'espère que ça aide!

0
mparis