GraphQL Query: Filtering not Working Properly
The matches operator in Sanity's GraphQL API uses tokenization, which means it splits both your search pattern and the document titles into individual words (tokens) and then checks if all the tokens from your search pattern appear anywhere in the title. This explains why you're seeing unexpected results.
When you query with title:{matches:"master the basics"}, the system tokenizes this into three separate words: "master", "the", and "basics". According to the GraphQL changelog, as of API version v2023-08-01: "Match patterns are now tokenized into terms, and all terms must be present for a match."
So your query returns documents where all three words appear in the title, regardless of order or position. Looking at your unexpected results:
- "The Gratitude Challenge: Yoga and Meditation" - contains "the"
- "Learn the Routine: Dance Choreography" - contains "the"
The issue is that "the" is a common word that appears in almost all your titles. The tokenization treats each word equally, so as long as "master", "the", and "basics" all appear somewhere in the title (even separated), it's considered a match. The word "the" appearing in "The Gratitude Challenge" satisfies one of your three required tokens.
Solutions:
Remove common words from your search pattern:
title:{matches:"master basics"}This will only look for documents containing both "master" and "basics", giving you more precise results.
Use GROQ instead of GraphQL for more flexible string matching. GROQ's match operator gives you similar tokenization but with more control, including wildcard support:
*[_type == "seriesType" && !(_id in path("drafts.**")) && isPublished == true && title match "master*basics*"]Add a slug or normalized field specifically for filtering. Create a field without common words like "the", "a", "an" for more precise searches.
Filter out unwanted results by adding additional constraints to your GraphQL query, such as checking for the presence of specific words:
where: { title: { matches: "master basics" } # Add other filters to narrow results }
The tokenization behavior is working as designed - it's meant to provide flexible text search across word boundaries rather than exact phrase matching. This is the same behavior you'll find in GROQ's match operator, which also tokenizes "content as words (i.e. split on whitespace and punctuation)."
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.