How to make nested parent page slug query more generic in Sanity?
Looking at your query, yes, it can definitely be written in a more generic way! Your current approach hardcodes the depth (3 levels) and array indices. Here are several approaches to make it more flexible:
The Challenge
GROQ doesn't support recursive traversal of parent references at arbitrary depth. You can't write something like parent->parent->... dynamically. However, there are some practical solutions depending on your use case:
Solution 1: Use Array Slice with Negative Index
If you know the slug path structure, you can work with the array more flexibly:
*[
slug.current == $slug[-1] &&
parentPage->slug.current == $slug[-2] &&
parentPage->parentPage->slug.current == $slug[-3]
]This uses negative indexing to access elements from the end of the array, making it slightly more readable.
Solution 2: Build a Path String for Comparison
If your documents have a computed path field or you can build one, you could do:
*[
path == "/" + array::join($slug[1..], "/")
]This assumes you have a path field that stores the full hierarchical path.
Solution 3: Use a Custom GROQ Function
For truly dynamic depth traversal, you could create a custom GROQ function (requires Growth plan or higher). This would allow you to define reusable logic for traversing parent chains.
Solution 4: Denormalize Your Data (Recommended)
The most practical solution for deep hierarchies is to denormalize by storing an ancestors array on each document:
{
slug: "page",
ancestors: [
{ _ref: "root-id" },
{ _ref: "parent-id" }
]
}Then your query becomes much simpler and works at any depth:
*[
slug.current == $slug[-1] &&
count(ancestors[@._ref in $ancestorIds]) == count($ancestorIds)
]The Reality
Unfortunately, GROQ does not support arbitrary-depth recursive parent traversal. The language is intentionally designed without recursion to maintain performance and predictability. As explained in the How Queries Work documentation, your current approach of explicitly chaining parent->parent-> is actually the standard pattern when you know the depth.
If you need to support variable depths, denormalizing with an ancestors array is the recommended Sanity pattern. This also significantly improves query performance for deep hierarchies since you avoid multiple reference lookups.
Would you like help implementing the ancestors approach? It typically involves adding a field to your schema and using a migration or document action to populate it when documents are created or updated.
Show original thread10 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.