GROQ conditional reference dereferencing not working in API 2021-03-25+
I see what's happening here! The syntax you're using with ^-> isn't actually a documented GROQ operator - it looks like you might have been combining ^ (parent scope) with -> (dereference) in a way that may have worked in an older parser or was part of custom code.
For your use case with a mixed array of references and objects, here's the correct approach in GROQ API version 2021-03-25 and later:
menuItems[]{
_type == "menuPage" => @->,
_type != "menuPage" => @
}What this does:
@represents the current item in the array iteration@->dereferences the current item if it's a reference- The conditional
_type == "menuPage" => @->only dereferences when the type ismenuPage - Other types (
internalLink,externalLink) pass through unchanged with@
You can also be more explicit about each type:
menuItems[]{
_type == "menuPage" => @->,
_type == "internalLink" => @,
_type == "externalLink" => @
}Alternative approach using coalesce:
As mentioned in the GROQ joins specification, you can use coalesce to elegantly handle mixed content:
menuItems[]{
...,
"resolved": coalesce(@->, @)
}This attempts to dereference first (@->), and if the item isn't a reference, it returns the object as-is (@). However, the conditional approach gives you more explicit control over which types get dereferenced.
Why this works:
The -> operator in GROQ internally executes a subquery to resolve references. When you use @-> in an array projection, you're telling GROQ to dereference the current item in the iteration. For non-reference items (your inline internalLink and externalLink objects), the dereference simply doesn't apply, so using the conditional ensures you only dereference what needs dereferencing.
The key is using @-> (not ^->) to dereference items within array projections!
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.