Querying for documents by reference in a post and tag schema
I can see the issue! Looking at your gist, you're trying to use $tags in tags[].tag but the problem is with how you're comparing the arrays. The in operator in GROQ checks if a single value exists in an array, but you're passing an array of tag references and trying to match them against dereferenced tag strings.
Here's the fix for your query:
export const getSuggestedPostsByTagsQuery = `{
"similarPosts": *[_type == "post" && slug.current != $slug && references(*[_type == "tag" && tag in $tags]._id)] | order(date desc, _updatedAt desc) [0...2] {
${postFields}
}
}`;And update your request to pass just the tag strings:
const { similarPosts } = await getClient(preview).fetch(
getSuggestedPostsByTagsQuery,
{
slug: params.slug,
tags: post.tags.map((tag) => tag.tag), // This is correct - array of tag strings
}
);How this works:
The references() function is specifically designed for querying by reference. It checks if any of the document's reference fields point to documents matching the inner query. The inner query *[_type == "tag" && tag in $tags]._id finds all tag document IDs where the tag string is in your array, then references() checks if the post references any of those tag documents.
Alternative approach if you want to be more explicit:
*[_type == "post" && slug.current != $slug && count((tags[]->tag)[@ in $tags]) > 0]This dereferences all the tags (tags[]->tag), checks which ones are in your $tags array, counts them, and only returns posts where at least one tag matches.
Both approaches will work, but references() is generally more performant for this type of reference matching since it leverages Sanity's indexing better, as discussed in the query optimization guide.
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.