
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeI totally feel your pain with the nested select() statements – they can get unwieldy fast! While GROQ doesn't have a built-in "switch" statement or pattern matching, there are a few approaches that can make your query more maintainable.
The best approach is to move some of the conditional logic to your application code and use GROQ parameters to pass in pre-computed values. This keeps your GROQ query cleaner and easier to test.
A cleaner approach is to construct different query strings based on your parameters in JavaScript:
function buildInsightsQuery({ order, insightType, filter }) {
const orderDir = order === "asc" ? "asc" : "desc";
let filterClause = `_type == $insightType`;
if (filter === "past") {
filterClause += ` && now() > date`;
} else if (filter === "future") {
filterClause += ` && now() < date`;
}
return `*[${filterClause}] | order(date ${orderDir})`;
}
// Usage
const query = buildInsightsQuery({ order: "asc", insightType: "insight", filter: "past" });
const result = await client.fetch(query, { insightType });If you want to keep it in GROQ, you can sometimes flatten nested selects using boolean operators:
"insights": *[
_type == ^.insightType
&& (
!defined(^.filter)
|| (^.filter == "past" && now() > date)
|| (^.filter == "future" && now() < date)
)
] | order(date select(^.order == "asc" => asc, desc))This uses the || (OR) operator to handle multiple conditions at once, which can be easier to read than deeply nested selects. The order() function can still use select() for the direction.
Another pattern is to create a projection that adds computed fields, then filter on those:
*[_type == ^.insightType] {
...,
"matchesFilter": select(
!defined(^.filter) => true,
^.filter == "past" => now() > date,
^.filter == "future" => now() < date,
false
)
}[matchesFilter] | order(date select(^.order == "asc" => asc, desc))This separates the filtering logic from the query structure, making it a bit more modular.
For complex conditional queries like yours, I'd recommend building the query string in JavaScript. It gives you:
The GROQ query language is powerful, but it's not designed to be a full programming language. When the logic gets complex, leveraging your application code is usually the right call. You can still use parameters for the actual values to keep things safe and maintainable, as explained in the GROQ Parameters documentation.
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