How to Query all the Documents that have the Same Start of the ID as the Current Document
The issue with your query is that match is designed for full-text search with tokenization, not for pattern matching with wildcards. For your use case of finding documents by ID prefix, you should use the string::startsWith() function instead.
Here's how to fix your query:
*[_type == "project"] | order(_updatedAt desc) {
_id,
'lang': __i18n_lang,
title,
'slug': slug.current,
"translated": *[_type == "project" && string::startsWith(_id, ^._id + "__i18n_")] {
_id,
'lang': __i18n_lang,
title,
'slug': slug.current
}
}The key changes:
- Use
string::startsWith()instead ofmatch- this does exact prefix matching - Reference the parent document's ID with
^._idto access the outer document's_idfield - Build the prefix pattern by concatenating
^._id + "__i18n_"to match your translation suffix pattern - Include the
_typefilter in the subquery to keep it efficient
If you want to get all translations (including other language versions), you could do:
*[_type == "project"] | order(_updatedAt desc) {
_id,
'lang': __i18n_lang,
title,
'slug': slug.current,
"allTranslations": *[_type == "project" && string::startsWith(_id, ^._id)][_id != ^._id] {
_id,
'lang': __i18n_lang,
title,
'slug': slug.current
}
}This filters for documents whose _id starts with the current document's _id, then excludes the current document itself with [_id != ^._id].
The match operator tokenizes text and treats special characters as word separators, which is why it doesn't work for precise ID matching. string::startsWith() is the right tool for prefix-based string matching in GROQ.
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.