
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeThe 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:
string::startsWith() instead of match - this does exact prefix matching^._id to access the outer document's _id field^._id + "__i18n_" to match your translation suffix pattern_type filter in the subquery to keep it efficientIf 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 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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store