Filtering nested arrays in GROQ without global scope

20 replies
Last updated: Dec 2, 2025
Is there a way to limit the scope of a filter within a groq query to the returned scope? Every query seems to be global (*[]), but I want to search within the context of a returned array of objects

*[_type == 'module' && slug.current == $module]{
  "chapters": chapters[]->{...}
}
I want to match against slug.current inside the returned
chapters
AI Update

You're absolutely right that filtering within the context of returned arrays requires a different approach than the global *[] pattern. The key is understanding how to filter after dereferencing.

Filtering dereferenced arrays

To filter chapters based on their slug.current field after dereferencing, you can apply a filter directly to the dereferenced array:

*[_type == 'module' && slug.current == $module]{
  "chapters": chapters[]->[slug.current == $chapterSlug]
}

This works because:

  1. chapters[]-> dereferences all chapter references, giving you an array of chapter documents
  2. [slug.current == $chapterSlug] filters that dereferenced array based on the slug field in the actual chapter documents

According to the pipeline components documentation, the filter component [<boolean>] iterates over elements of an array and returns only those where the expression evaluates to true. The documentation notes that "this operator is actually the filter pipeline component in disguise, since it has an implicit | operator before it."

Alternative: Filter before dereferencing

If you need to filter based on properties of the reference itself (like _key or _ref), you can filter before dereferencing:

*[_type == 'module' && slug.current == $module]{
  "chapters": chapters[_key == $someKey]->
}

However, this won't work for filtering by fields in the referenced documents (like slug.current), since those fields don't exist on the reference object itself—they only exist in the referenced document.

Combining operations

You can chain multiple operations together on dereferenced arrays:

*[_type == 'module' && slug.current == $module]{
  "chapters": chapters[]->[slug.current match $searchTerm] | order(orderRank asc)[0..4]
}

This filters the dereferenced chapters, then uses the pipe operator for ordering and slicing—all within the projection scope, exactly what you're looking for! The pipe operator is required for functions like order() but the filter syntax works directly on arrays.

Show original thread
20 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.

Was this answer helpful?