Access array item index in GROQ projection for filtered arrays
Unfortunately, GROQ doesn't have a built-in way to access the current index of an item during array projection. There's no @index operator or similar construct that gives you the position of an element as you iterate through an array.
However, there are several workarounds depending on your use case:
The Pattern You Discovered (Recommended for Most Cases)
Based on the Sanity Answers thread, the most practical solution is to fetch the array shape alongside your filtered data:
*[_type == "issue"][0] {
...articles[someCondition][0],
"articleInfo": @ {
...,
"arrayShape": ^.articles[] {
_type,
slug,
_key
}
}
}This gives you the complete ordered array structure, allowing your frontend to determine the next/previous items based on the current item's identifier (_key or slug). While this requires some client-side logic, it's bandwidth-efficient since you're only fetching minimal identifying fields for the full array.
Alternative Approaches
1. Using negative slice indices:
According to the Pipeline Components documentation, GROQ supports negative indices in slices, where -1 refers to the last element:
someArray[-1] // Last item
someArray[-2] // Second to last
someArray[2..-1] // From third element to the lastThis is useful for accessing items from the end of an array, but doesn't help you get the "next" item during projection.
2. Parent reference with the ^ operator:
Use the @ (current item) and ^ (parent) operators to reference sibling items:
*[_type == "document"] {
"items": items[] {
title,
"allSiblings": ^.items[]._key
}
}Though accessing a specific "next" item by index from within the projection remains challenging without knowing the current position.
3. Multiple queries approach:
If you absolutely need to avoid client-side logic, you could structure your data differently or make separate queries for each item, but as you noted, this is less efficient.
Why This Limitation Exists
As noted in the community discussion, relying on array indices for content relationships is generally fragile—if the array order changes between queries, indices become unreliable. GROQ's design encourages using stable identifiers (_key, _id, slug) for relationships instead.
For your use case of linking to the next article in a user-ordered list, the array shape pattern is the most robust solution. It gives you the ordering context you need while maintaining referential integrity through unique identifiers rather than positional indices. You fetch the minimal array structure (just identifiers) alongside your detailed data, then handle the next/previous logic client-side with the stable ordering information.
This approach is bandwidth-efficient because you're only including lightweight identifiers for the full array, not the complete content of every item. Your frontend can then match the current item's _key or slug in the array shape to determine its neighbors—which is safer than relying on numeric indices that could shift between queries.
Show original thread4 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.