GROQ: Filter slug.current excluding multiple patterns with match operator

9 replies
Last updated: Jan 27, 2026
Good day 🙂I’m trying to use GROQ to filter out a
list of pages to exclude if the
slug.current
contain either
/press
or
/blog
Using
match
because the
slug.current
can be
/press/XXX
or
/blog/XXX

The following works

.filter('_type == "page" && !(slug.current match "/press") && !(slug.current match "/blog")')

I’m looking into simplified the match to either but the following doesn’t work. Any advice?

.filter('_type == "page" && !(slug.current match ["/press", "/blog"])')
AI Update

The match operator in GROQ doesn't support matching against an array of patterns directly. Your working solution with separate conditions is actually the correct approach! However, there's a better way to handle this.

The match operator is designed for full-text search with tokenization, not exact string pattern matching. According to the match operator documentation, it tokenizes text and treats special characters like / as word separators, which makes it less ideal for slug matching.

The better solution: Use string::startsWith() instead, which is specifically designed for prefix matching:

*[_type == "page" && 
  !string::startsWith(slug.current, "/press") && 
  !string::startsWith(slug.current, "/blog")
]

Why this is better:

  • string::startsWith() does exact prefix matching without tokenization
  • It's more performant for this use case
  • The intent is clearer in your code
  • It's the recommended approach for prefix matching

Why your array syntax didn't work: The match operator doesn't accept arrays as the pattern argument. It expects a single string pattern with optional wildcards (*), not an array of patterns. There's no built-in OR functionality, pipe syntax, or alternation for multiple patterns in a single match expression - you have to use separate conditions like you did.

If you really want an array-based approach, you could do something like this, though it's more complex:

*[_type == "page" && 
  !(["/press", "/blog"] match string::split(slug.current, "/")[1])
]

But honestly, stick with string::startsWith() - it's cleaner, more readable, and semantically correct for checking URL prefixes. Your original working solution is also perfectly fine if you prefer to keep using match!

Show original thread
9 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.

Was this answer helpful?