This Friday: Hear from Sanity + Vercel experts on AI and better personalization in e-commerce

GROQ: Query nested object text content and filter by matching word

6 repliesLast updated: Nov 29, 2025

Hey! i'm new to groq and I'm struggling with understanding how I can make a query on a nested object.Here's what I'm trying to do: I'm trying to get a list of all the slugs where the text (lorem example below) matches a certain word. Any help would be appreciated, I'm a bit inexperienced with groq
🙂

{

"_createdAt": "2022-07-01T06:15:15Z",

"_id": "ipsum",

"_rev": "lorem",

"_type": "post",

"_updatedAt": "2022-07-07T04:00:02Z",

"contentBlocks": [

{

"_key": "somenu12312",

"_type": "textContent",

"mainText": [

{

"_key": "somenum123123",

"_type": "block",

"children": [

{

"_key": "othernum123213",

"_type": "span",

"marks": [],

"text": "omnis-aut-voluptatem Culpa beatae omnis corporis in enim. Sit quo mollitia et omnis ea sit praesentium rerum."

}

],

"markDefs": [],

"style": "normal"

}

]

}

],

"slug": {

"_type": "slug",

"current": "ipsum"

},

"title": "lorem"

}
AI Update

Looking at your data structure, you need to search through nested arrays to find text within your Portable Text blocks. Here's how to do it:

*[_type == "post" && contentBlocks[].mainText[].children[].text match "omnis-aut-voluptatem"]{
  slug
}

This will return all posts where any text in your nested structure matches the word you're searching for. The key is understanding how GROQ handles nested arrays - you use [] to "flatten" each level of the array structure.

Breaking down the path:

The match operator performs tokenized text search, so it'll find whole words within your text. It breaks text into searchable terms, so searching for "omnis" would match "omnis-aut-voluptatem" since the dash acts as a word separator.

To get just the slug values as a simple array:

*[_type == "post" && contentBlocks[].mainText[].children[].text match "omnis"]{
  "slug": slug.current
}

Pro tip: If you need to search for multiple words or do more complex searches, you can combine conditions:

*[_type == "post" && (
  contentBlocks[].mainText[].children[].text match "omnis" ||
  contentBlocks[].mainText[].children[].text match "beatae"
)]{
  slug
}

The match operator is great for full-text search, but if you need exact string matching or prefix matching, you'd want to use string functions like string::startsWith() instead.

Show original thread
6 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