GROQ query to find nested custom blocks with invalid marks array
I can see you're struggling with filtering deeply nested arrays in GROQ. This is a common challenge, and the key is understanding how GROQ handles array traversal in filter conditions versus projections.
The issue you're encountering is that when you write something like:
brodtekst[_type == 'hjelpeartikkel.expandCollapse'].innhold[_type == 'bilde'].marks[]This creates a flattened array of all marks from all matching bilde objects across all matching brodtekst items. When you then check != null, you're not checking whether specific documents have marks, but rather whether this flattened array contains anything.
Here's a working approach using nested count() functions to check for the existence of marks at the right nesting level:
*[_type == 'hjelpeartikkel' &&
count(brodtekst[
_type == 'hjelpeartikkel.expandCollapse' &&
count(innhold[_type == 'bilde' && defined(marks)]) > 0
]) > 0
]{
_id,
"problematicBlocks": brodtekst[_type == 'hjelpeartikkel.expandCollapse']{
innhold[_type == 'bilde' && defined(marks)]{
_key,
_type,
marks
}
}
}This query works by:
- Using
count()at each nesting level to properly evaluate whether matching items exist - The inner filter
innhold[_type == 'bilde' && defined(marks)]only matchesbildeobjects that have amarksfield - The outer
count(...) > 0checks if there's at least one matchingexpandCollapseitem - In the projection, the same filter returns only the problematic blocks
If you want to be more specific and only find bilde objects where marks is an array with actual content (not just defined but empty), you can use:
*[_type == 'hjelpeartikkel' &&
count(brodtekst[
_type == 'hjelpeartikkel.expandCollapse' &&
count(innhold[_type == 'bilde' && count(marks) > 0]) > 0
]) > 0
]The count(marks) > 0 ensures you're only matching bilde objects where the marks array actually contains elements.
Why your original attempts didn't work:
brodtekst[].innhold[].marks[] != nullflattens all marks across all documents into a single array, then compares that array to null (which will always be true if any marks exist anywhere)- While chained array syntax like
array[].nestedArray[]works for projections, when you're using it in filter conditions with comparisons, the flattening behavior can produce unexpected results - Using
count()at each nesting level gives you explicit control over what you're checking at each depth
If you're still getting unexpected results, you might also try using length(marks) > 0 as an alternative to count(marks) > 0, though they should behave similarly for arrays. Another option is to add && length(marks) > 0 for extra certainty that it's a non-empty array.
Show original thread5 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.