✨Discover storytelling in the AI age with Pixar's Matthew Luhn at Sanity Connect, May 8th—register now

How to use GROQ to Write Loops

10 replies
Last updated: Jun 29, 2021
I'm trying to use GROQ to save me writing some loops in the front end.
I have an array of tasks, in this array there is a property named "usedTime" indicating how long has been spent on a task, only some of the tasks have this value.

The result I'm after is one array (one dimentional) containing the usedTime data, I can handle null values in my front end but if sanity supports omitting them that would be awesome

Attached is the result of the query

*[_type == "internalCustomers" && '<mailto:myMail@mail.com|myMail@mail.com>' in users[]->email]{
  "totalHours": tasks[].tasks[], 
}
I know my naming work needs improving
😉
I've tried several methods

  "totalHours": tasks[].tasks->usedTime, 
  "totalHours": tasks[].tasks[]->usedTime, 
  "totalHours": tasks[].tasks[]->.usedTime, 
  "totalHours": tasks[].tasks.usedTime, 
All my attempts return "null"
Any idea on how I can achive this?
🙂
Jun 29, 2021, 4:33 PM
I’m wondering if there might be another array to include in your query, given the double-nesting after
totalHours
in your third array item.
Schema:

export default {
  name: 'andreas',
  type: 'document',
  fields: [
    {
      name: 'tasks',
      type: 'array',
      of: [
        {
          name: 'firstObj',
          type: 'object',
          fields: [
            {
              name: 'tasks',
              type: 'array',
              of: [
                {
                  name: 'secondObj',
                  type: 'object',
                  fields: [
                    {
                      name: 'tasks',
                      type: 'array',
                      of: [
                        {
                          name: 'thirdObj',
                          type: 'object',
                          fields: [
                            {
                              name: 'usedTime',
                              type: 'number'
                            },
                          ],
                        },
                      ],
                    },
                  ],
                },
              ]
            }
          ]
        }
      ]
    }
  ]
}
GROQ query:

*[_type == 'andreas'] {
  'totalHours': tasks[].tasks[].tasks[].usedTime
}
Returns:

"result": [
  0: {
    "totalHours": [
      0: 34
    ]
  }
]
Jun 29, 2021, 7:06 PM
As for removing null values, I believe you could try
[count(totalHours) > 0]
at the end of your query. In my example above, it came after the
}
at the end of the projection.

*[_type == 'andreas'] {
  'totalHours': tasks[].tasks[].tasks[].usedTime
}[count(totalHours) > 0]
Jun 29, 2021, 7:09 PM
Hey Geoff, yes it seems to be another arrayed hidden in here. Can't really see why
Your suggestion makes sense, but does not work. I can't see a name for the additional array either

Results of

*[_type == "internalCustomers" && '<mailto:andreas.jacobsen@inklud.no|andreas.jacobsen@inklud.no>' in users[]->email]{  
  'totalHours': tasks[].tasks[].tasks[]
}
is null

If I remove the last task-attribute I get this response

https://ad47v47a.api.sanity.io/v1/data/query/production?query=*%5B_type%20%3D%3D%20%22in[…]%20%20%27totalHours%27%3A%20tasks%5B%5D.tasks%5B%5D%0A%7D
Jun 29, 2021, 7:22 PM
Hey Geoff, yes it seems to be another arrayed hidden in here. Can't really see why
Your suggestion makes sense, but does not work. I can't see a name for the additional array either

Results of

*[_type == "internalCustomers" && '<mailto:andreas.jacobsen@inklud.no|andreas.jacobsen@inklud.no>' in users[]->email]{  
  'totalHours': tasks[].tasks[].tasks[]
}
is null

If I remove the last task-attribute I get this response

https://ad47v47a.api.sanity.io/v1/data/query/production?query=*%5B_type%20%3D%3D%20%22in[…]%20%20%27totalHours%27%3A%20tasks%5B%5D.tasks%5B%5D%0A%7D
Jun 29, 2021, 7:22 PM
you might want to use the new api version btw
Jun 29, 2021, 7:44 PM
Thanks, using v2021-03-25 in my front end, will change to that in studio as well. Same problem with v2021-03-25
Edit: Sorry my mistake, using the newer API I get the result I want
🙂
Jun 29, 2021, 7:45 PM
Also, this might be the thing you want?
*[_type == "internalCustomers" && '<mailto:andreas.jacobsen@inklud.no|andreas.jacobsen@inklud.no>' in users[]->email]{  
  'totalHours': tasks[tasks != null].tasks
}
Jun 29, 2021, 7:49 PM
GROQ is amazingI tried your not null example Knut, but weirdly I get one null value
But this is pretty easy to handle in the front end
Jun 29, 2021, 7:54 PM
Try
*[_type == "internalCustomers" && '<mailto:andreas.jacobsen@inklud.no|andreas.jacobsen@inklud.no>' in users[]->email]{  
  'totalHours': tasks[tasks != null].tasks[usedTime != null].usedTime
}[count(totalHours) > 0]

Jun 29, 2021, 7:57 PM
thanks! That worked, I'll remove count because I just remember that count and sum is not the same thing. GROQ just saved me a bunch of loops I'd have to maintain and try to understand again some time in the future 🙂 Should have thought of tasks being able to be null as well
Jun 29, 2021, 8:00 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?