How to query nested arrays and filter by property in GROQ (prizes with affiliations)
Great question! Filtering nested arrays in GROQ can be tricky at first, but once you understand the pattern, it becomes quite powerful. Let me walk you through both scenarios using the Nobel Prize dataset from GROQ Arcade.
1. Filtering documents based on nested array properties
To retrieve only people who have a prize with an affiliation to the city of "Leiden", you need to use the count() function because GROQ doesn't automatically "drill down" through nested arrays the way you might expect:
*[count(prizes[].affiliations[city == "Leiden"]) > 0]This works because:
prizes[]flattens the prizes array.affiliations[city == "Leiden"]filters affiliations within each prizecount()checks if any matching affiliations exist- The outer filter
> 0ensures we only get people with at least one match
Important: You can't write *[prizes[].affiliations[].city == "Leiden"] because the [] operators create arrays at each level, and you'd end up comparing an entire array to "Leiden" rather than individual values.
2. Filtering AND projecting nested data
For your second question—where you want to "clean up" the results to show only relevant prizes and affiliations—you need to apply the same filtering logic in your projection:
*[count(prizes[].affiliations[city == "Leiden"]) > 0] {
_id,
firstname,
surname,
"prizes": prizes[count(affiliations[city == "Leiden"]) > 0] {
...,
"affiliations": affiliations[city == "Leiden"]
}
}This query does three things:
- Filters documents at the root level (only people with Leiden affiliations)
- Filters the prizes array to include only prizes that have Leiden affiliations
- Filters the affiliations array within each prize to show only Leiden affiliations
The result is a clean dataset where you can immediately see which specific prize and affiliation caused the match—super helpful when debugging complex filters or presenting filtered data to users.
The key pattern
The pattern here is: when filtering nested arrays, use count(array[condition]) > 0 at each level. This is covered in the GROQ pipeline components documentation, which explains how filters work with arrays.
This same technique applies to any nested structure—whether it's products with variants with pricing plans (as mentioned in the Sanity community discussion about this exact topic), or any other deeply nested content model in your Sanity dataset.
Show original thread9 replies
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.