Querying multiple types in Sanity with vanilla JS and using webhooks for Netlify rebuilds
You can query multiple _type values using the in operator in GROQ! The syntax looks like this:
*[_type in ["article", "category"]]This will return all documents where the _type is either "article" OR "category". The in operator checks if a value exists in an array, which is exactly what you need for filtering by multiple document types.
Here's a more complete example with a projection:
*[_type in ["post", "page", "product"]]{
_id,
_type,
title,
slug
}This query fetches all documents that are either posts, pages, or products, and returns their ID, type, title, and slug fields.
If you tried using an array directly in the filter like *[_type == ["article", "category"]], that won't work because you're comparing _type to an array rather than checking if it exists within an array. The in operator is the correct way to handle this.
You can also combine this with other filter conditions using the && (AND) or || (OR) operators:
*[_type in ["article", "blogPost"] && publishedAt > "2024-01-01"]The key thing to remember is: use in when you want to check if a field's value matches any value in an array. This is documented in the GROQ pipeline components section, though it can be easy to miss!
*[_type in ["typeA", "typeB"]]should do it I think. The result might be confusing though if you have fields with the same name in both types.
*[_type in ["typeA", "typeB"]]{
_type == "typeA" => {
// field selection for typeA
},
_type == "typeB" => {
// field selection for typeB
}
}"expected '}' following object body"
Here is what I have:
let encodedFilter = encodeURIComponent('[_type in ["cabinet", "representative", "supremeCourt", "senator"]]');
let encodedProjection = encodeURIComponent(`_type== "cabinet" => {"_type"}, _type== "representative" => {"_type"}, _type== "supremeCourt" => {"_type"}, _type== "senator" => {"_type"}`)
fetch(`<https://6dyl9k59.api.sanity.io/v2021-01-01/data/query/production?query=*${encodedFilter}{${encodedProjection}}>`)v1of the API since you have
2021-01-01specified. If you configure it to use a date later than
2021-03-25do you still get the error?
2022-01-01! I've updated it to that, and I still get the error
const query = `[_type in ["cabinet", "representative", "supremeCourt", "senator"]]{
_type == 'representative' => {
//fields you're hoping to get from representative document
}
//other types
}`const query = `[_type in ["cabinet", "representative", "supremeCourt", "senator"]]{
_type == 'representative' => {
"_type"
}
//etc
}`let encodedProjection = encodeURIComponent(`
_type == "cabinet" => {"_type, cabinetName, 'confirmationCommittee': confirmationCommittee[]->.senateCommitteeName, position, succession, cardLink, cardLink2, cardBackImage"},
_type == "representative" => {"_type, representativeName, state->, party->, district, assumedOffice, 'leadershipPositions': leadershipPositions[]->.houseLeadershipName, 'committeeAssignments': committeeAssignments[]->.CommitteeName, cardLink, cardBackImage"},
_type == "supremeCourt" => {"_type, circuitAssignments[], justiceName, memberSince, nominatedBy, position, segalCoverScore, cardLink, cardBackImage"},
_type == "senator" => {"_type, senatorName, party->, state->, leadershipPositions[], 'committeeAssignments': committeeAssignments[]->.senateCommitteeName, reelectionYear, cardLink, assumedOffice, cardBackImage"}`
){description: "Attribute or a string key expected", type: "queryParseError"}let encodedFilter = encodeURIComponent('[_type in ["cabinet", "representative", "supremeCourt", "senator"]]');
let encodedProjection = encodeURIComponent(`
_type == "cabinet" => {_type, cabinetName, 'confirmationCommittee': confirmationCommittee[]->.senateCommitteeName, position, succession, cardLink, cardLink2, cardBackImage},
_type == "representative" => {_type, representativeName, state->, party->, district, assumedOffice, 'leadershipPositions': leadershipPositions[]->.houseLeadershipName, 'committeeAssignments': committeeAssignments[]->.CommitteeName, cardLink, cardBackImage},
_type == "supremeCourt" => {_type, circuitAssignments[], justiceName, memberSince, nominatedBy, position, segalCoverScore, cardLink, cardBackImage},
_type == "senator" => {_type, senatorName, party->, state->, leadershipPositions[], 'committeeAssignments': committeeAssignments[]->.senateCommitteeName, reelectionYear, cardLink, assumedOffice, cardBackImage}
`)
fetch(`<https://6dyl9k59.api.sanity.io/v2022-01-01/data/query/production?query=*${encodedFilter}{${encodedProjection}}>`)
.then(res => res.json())
.then(justice => justice.result.forEach((item)=>{
cardGrid.append(createCard(item));
}),
main.append(cardGrid))encodeURI. I'll try to work up an example for you.
encodeURI. I'll try to work up an example for you.
A soft suggestion: have an article/video/doc showing how to do a vanilla JS, frameworkless project that auto-triggers a rebuild upon some sort of "rebuild" button or something. It seems like that's a core use-case that isn't covered in your current docs, no?
It allows for unlimited number of types, filters, and sorts without coding any specifics other than the projections, which are done in one big array. I'm not done, but if I understand this all correctly, it would be a really powerful piece of logic
//Set up query vars
const projectId = '6dyl9k59';
const apiDate = 'v2022-01-01';
const dataSet = 'production';
const encodedProjection = encodeURIComponent(`_type == 'secretaries' => {_type, name, 'confirmationCommittee': confirmationCommittee[]->.senateCommitteeName, position, succession, cardLink, cardLink2, cardBackImage}, _type == 'representatives' => {_type, name, state->, party->, district, assumedOffice, 'leadershipPositions': leadershipPositions[]->.houseLeadershipName, 'committeeAssignments': committeeAssignments[]->.CommitteeName, cardLink, cardBackImage}, _type == 'justices' => {_type, circuitAssignments[], name, memberSince, nominatedBy, position, segalCoverScore, cardLink, cardBackImage}, _type == 'senators' => {_type, name, party->, state->, leadershipPositions[], 'committeeAssignments': committeeAssignments[]->.senateCommitteeName, reelectionYear, cardLink, assumedOffice, cardBackImage}`);
const type = params.type.replace(' ', ', ');
const decodedFilter = decodeURI(params.filter);
const preFilter = decodedFilter.replace('+', ' && ');
const filter = preFilter.replace('_', ' == ');
let leftFilter;
let rightFilter;
let encodedFilter;
//check for filter parameters
function createFilter(){
if(params.filter) {
leftFilter = `[_type in [${type}] && ${filter}]`;
} else {
leftFilter = `[_type in [${type}]]`;
}
return leftFilter;
};
createFilter();
//check for sorting parameters, then create encoded filter
function createSort() {
if(params.sort) {
const sort = params.sort.replace('_', ' ')
rightFilter = `order(${sort})`;
encodedFilter = encodeURIComponent(`${leftFilter} | ${rightFilter}`);
console.log(`${leftFilter} | ${rightFilter}`)
} else {
encodedFilter = encodeURIComponent(leftFilter);
console.log(`${leftFilter}`)
}
return encodedFilter;
}
createSort();
//fetch data & call the createCard function
fetch(`https://${projectId}.<http://api.sanity.io/${apiDate}/data/query/${dataSet}?query=*${encodedFilter}{${encodedProjection}}`)|api.sanity.io/${apiDate}/data/query/${dataSet}?query=*${encodedFilter}{${encodedProjection}}`)>
.then(res => res.json())
.then(cardData => cardData.result.forEach((item)=>{
cardGrid.append(createCard(item));
}),
main.append(cardGrid));😬
https://www.sanity.io/plugins/sanity-plugin-dashboard-widget-netlify
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.