See how we built our intranet. Live + Q&A, June 30

GROQ query to find nested custom blocks with invalid marks array

5 repliesLast updated: Dec 1, 2025

We have managed to import some bad data in some documents, in a nested custom component, and I am trying to write a groq query to find what documents contain bad data.The problem is that some articles have ended up with a mark on a custom block, which ends up giving an error when we try to render it, because the marks aren’t a part of the schema. an example of such a bad block:

{
  "_key": "afd98068bfc1",
  "_type": "bilde",
  "altText": "",
  "caption": "",
  "image": {
    "_type": "image",
    "asset": {
      "_ref": "image-b3d77a3ad3970d959d3bf83d6d2c02ad320cbb71-1000x681-jpg",
      "_type": "reference"
    }
  },
  "marks": [
    {
      "_key": "3c540f80b489",
      "_type": "link",
      "href": "<https://some-url>"
    }
  ]
},
this lives in a nested type, so the structure is something like this

brodtekst[_type == 'hjelpeartikkel.expandCollapse'].innhold[_type == 'bilde']
and I am trying to find all documents containing
bilde
with the bad
marks
array, but I can’t seem to find the right filtering to useI have tried something like this:

*[_type == 'hjelpeartikkel'
  &amp;&amp; brodtekst[_type == 'hjelpeartikkel.expandCollapse'].innhold[_type == 'bilde'].marks[] != null]{
  _id,
    brodtekst[_type == 'hjelpeartikkel.expandCollapse'] {
      innhold[_type == 'bilde'] {
        ...
      }
    }
}
but that ends up returning documents where there are no
marks
, I’ve also tried to
count(brodtekst[_type == 'hjelpeartikkel.expandCollapse'].innhold[_type == 'bilde'].marks[]) &gt; 0
and similar things, but they all end up either matching 0 documents, or too many documents. any pointers on how I can achieve this filter, or is it easier to just fetch all and manually go through them in javascript?
AI Update

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:

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:

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 thread
5 replies

Was this answer helpful?

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.

Related contributions