15

7 challenges for querying with GROQ

 4 years ago
source link: https://dev.to/mornir/7-challenges-for-querying-with-groq-3p0p
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

:page_with_curl: Introduction

Developers who are lucky to work with the headless CMS from Sanity have the opportunity to use a leaner and more expressive alternative to GraphQL: GROQ ( Gr aph-Relational O bject Q ueries).

The Sanity team recently launched groq.dev . There you can easily test out the GROQ syntax and play with it, without having to create a Sanity project.

I created 7 challenges that are relatively difficult. Before you try to tackle them, you should familiarize yourself with the GROQ specs by reading this introduction and having a look at this cheat-sheet .

:muscle: Challenges

Now you should be ready for the challenges on the Pokédex dataset :

  1. Find the weakest Pokémon overall. In other words, when comparing the sum of the base stats, return the Pokémon (only one!) with the lowest score.
  2. Return an array containing all and only the Pokémon names in English.
  3. List the numbers of Pokémon for the grass , fire and water types.
  4. List all the Pokémon that are only of water type. For each, return their ID, their names only in English and all their stats. Order them by their HP in descending order.
  5. Return the percentage of single-type Pokémon, rounded to the nearest integer.
  6. List the Pokémon based on the number of letters in their English name, from the longest string to the shortest string.
  7. Group the Pokémon in three categories (strong, average, weak) based on their attack stat. attack above 124 = strong; attack between 83 and 124 = average; attack below 83 = weak. Order the Pokémon by their attack from the lowest to the highest stat. Return their names, their attack stat and an evaluation property containing the value strong , average or weak .

:bulb: Solution

If you just want to see the queries without any explanations, you can read them in this gist .

Challenge 1: The one with the lowest base stats

UjMvUnR.jpg!web

Query

*[]{
  "overall": base.HP + base.Attack + base.Defense + base["Sp. Attack"] + 
             base["Sp. Defense"] + base.Speed,
  "name": name.english,
}|order(overall)[0]

Response

    {
      "overall": 175,
      "name": "Wishiwashi"
    }

Explanation (line by line)

  1. An empty filter means that all Pokémon will be selected
  2. Addition all the stats (same syntax as JavaScript for accessing properties)
  3. Return the name of the Pokémon
  4. Order by the overall property calculated above and only return the first element (the order is ascending by default).

Challenge 2: All and only the names

Query

*[].name.english

Response

    [
      "Bulbasaur",
      "Ivysaur",
      "Venusaur",
        ...
    ]

Explanation

Select all Pokémon and return an array of values only (without object wrapper) for the property english . If you use a projection with the brackets syntax, you would end up with an array of objects.

Challenge 3: Grass, fire and water

Query

{
      "Grass": count(*["Grass" in type]),
      "Fire": count(*["Fire" in type]),
      "Water": count(*["Water" in type]),
    }

Response

    {
      "Grass": 97,
      "Fire": 64,
      "Water": 131
    }

Explanation (line by line)

  1. You can wrap multiple selections in brackets.
  2. Return the number of Pokémon with Grass in their type and store the number in the Grass property.
  3. Idem for Fire and Water

Challenge 4: water-type Pokémon

A3IrU3B.png!web

Query

*['Water' in type && length(type) == 1]{
      id,
      "name": name.english,
      base
    }|order(base.HP desc)

Response

    [
    {
        "id": 321,
        "name": "Wailord",
        "base": {
          "HP": 170,
          "Attack": 90,
          "Defense": 45,
          "Sp. Attack": 90,
          "Sp. Defense": 45,
          "Speed": 60
        }
      },
     ...
    ]

Explanation (line by line)

  1. Filter Pokémon by type water and with only one type. The length function returns the length of an array.
  2. Projection: only return the id, the English name and all the stats.
  3. Sort the results by the HP in descending order.

Challenge 5: percentage of single type Pokémon

Query

{
      "percentage": round(count(*[length(type) == 1]) * 100 / count(*[]))
    }

Response

    {
      "percentage": 50
    }

Explanation

All standard arithmetic operations are supported in GROQ: get the number of single type Pokémon times 100 and divided by the total number of Pokémon in the dataset. (50% of Pokémon only have one type :hushed:)

Challenge 6: The longest name

V7jaUjE.png!web

Query

*[]{
      "name": name.english,
      "length": length(name.english)
    }|order(length desc)

Response

    [
      {
        "name": "Crabominable",
        "length": 12
      },
      {
        "name": "Fletchinder",
        "length": 11
      },
     ...
    ]

Explanation (line by line)

  1. An empty filter means that all Pokémon will be selected
  2. Projection with English name and the value of the length function, which can also return the length of a string.
  3. Sort the results by the length property calculated above, in descending order.

Challenge 7: The weak, the average and the strong

Query

*[]|order(base.Attack){
  "name": name.english,
  "attack": base.Attack,
  "evaluation": select(
  base.Attack  > 124  => "strong",
  base.Attack > 83 => "average",
  "weak"
)}

Response

[
  {
    "name": "Chansey",
    "attack": 5,
    "evaluation": "weak"
  },
  ...
]

Explanation (line by line)

  1. The ordering can also happen right after the filtering. In this case, the filtering doesn't work after the projection for some reason (probably because of the select function)
  2. Projection with the name, the attack and a conditional. If none of the conditions are met, weak is returned.

:relieved: Closing words

I hope you had fun playing around with GROQ and solving the challenges. If you caught a mistake or found alternative queries, don't hesitate to leave a comment.

:snake: The GROQ logo in the upper right part hides an Easter egg. Have you found it?

Image sources:

Pokédex: https://dribbble.com/shots/2908884-I-Saw-It-On-Twitch-Pokedex

Wishiwashi: https://bulbapedia.bulbagarden.net/wiki/Wishiwashi_(Pokémon)

Wailord: https://www.serebii.net/pokedex-swsh/wailord/

Crabominable: https://www.pokemon.com/us/pokedex/crabominable


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK