GROQ query for array with mixed objects and references
I can see the issue you're running into. When you have an array with mixed content (both primitive values like strings and references), you need to handle them differently in your GROQ query.
The problem is that the -> operator only works on references (objects with a _ref field), so when you use contacts[] ->, it tries to dereference everything in the array - which makes the plain strings become null. Conversely, contacts[] without the dereference operator gives you the raw reference objects instead of the actual address documents.
The solution is to use the coalesce function combined with the @ symbol (which refers to the current element in the array):
*[_type == 'person'][0] {
name,
contacts[] {
"value": coalesce(@->, @)
}
}Here's what's happening:
@->attempts to dereference the current array item (works for references)@returns the current item as-is (works for primitives)coalescereturns the first non-null value, so it'll use@->for references and fall back to@for plain strings
If you want to preserve the structure and make it clearer what type each item is, you could use the select function with defined(_ref) to check if something is a reference:
*[_type == 'person'][0] {
name,
contacts[] {
select(
defined(_ref) => @->,
@
)
}
}Or for a flatter structure:
*[_type == 'person'][0] {
name,
"contacts": contacts[]{
coalesce(@->, @)
}
}The key insight is that you need to conditionally apply the dereference operator based on whether the item is actually a reference. The coalesce(@->, @) pattern is the most common and elegant way to handle this mixed array scenario in GROQ, as mentioned in the GROQ reference documentation.
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.