How to pass dynamic category ID to GROQ query in getStaticProps with slug param
I can see your issue! You're hardcoding the category ID ("1b65f627-7d10-4a35-9062-41e9245ff272") in your GROQ query instead of using the dynamic _id from the fetched category. Here's how to fix it:
The Problem:
Your query fetches the category data first, but then uses a hardcoded ID in the subquery instead of referencing the current category's _id.
The Solution:
Use the ^ parent operator in GROQ to reference the parent document's _id in your subquery:
export async function getStaticProps({ params, preview = false }) {
const query = groq`
*[_type == "blogCategory" && slug.current == $slug][0]{
_id,
title,
description,
slug,
image,
"blogCategory": *[_type=='article' && references(^._id)]
}
`;
const queryParams = { slug: params.slug };
const data = await getClient(preview).fetch(query, queryParams);
return {
props: {
preview,
siteSettings: await fetchGlobalSettings(),
allCategories: await sanity.fetch(groq`
*[_type == "blogCategory" && !(_id in path('drafts.**'))] {...}
`),
data: {
page: data, // data is already a single item now
query,
queryParams,
},
},
};
}Key changes:
Added
[0]after the first filter to get a single category document instead of an array (so you don't needfilterDataToSingleItem)Used
references(^._id)instead of hardcoding the ID. The^operator references the parent document (the category), andreferences()checks if the article'sblogCategoriesarray contains a reference to that category's_idSimplified the data structure since we're now returning a single object instead of an array
Alternative approach if you prefer using query parameters:
const query = groq`
*[_type == "blogCategory" && slug.current == $slug][0]{
_id,
title,
description,
slug,
image,
"blogCategory": *[_type=='article' && references($categoryId)]
}
`;
const category = await getClient(preview).fetch(
groq`*[_type == "blogCategory" && slug.current == $slug][0]._id`,
{ slug: params.slug }
);
const queryParams = { slug: params.slug, categoryId: category };
const data = await getClient(preview).fetch(query, queryParams);However, the first approach with ^._id is cleaner and requires only one query.
Update your component to handle the simplified data structure:
const BlogView = (props) => {
const { data, preview, siteSettings = {}, allCategories } = props;
const { data: previewData } = usePreviewSubscription(data?.query, {
params: data?.queryParams ?? {},
initialData: data?.page,
enabled: preview,
});
const page = previewData;
if (!page || !page.blogCategory) return null;
return (
<Layout siteSettingData={siteSettings}>
{page.blogCategory.map((item, i) => (
<BlogItem data={item} key={item._id || i} />
))}
</Layout>
);
};The references() function is the proper way to check if a document has a reference to another document in an array field. This will dynamically filter articles based on whichever category page you're viewing!
Show original thread9 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.