✨Discover storytelling in the AI age with Pixar's Matthew Luhn at Sanity Connect, May 8th—register now

Making GROQ params optional in Next.js frontend API endpoint query

18 replies
Last updated: Jan 19, 2022
Sanityland! Is there a way to make GROQ params optional?
ie. I want to conditionally provide a filtering param to a GROQ query. If no param is provided, don't filter. If provided, filter.

This is my current solution:

*[_type == 'feed' ${id ? ' && _id == $id' : ''}]
Is there a way to do this without JS template literals?
Oct 12, 2021, 6:45 PM
Unfortunately, you can't apply something like this within your query. What's the context that you're using this in? Can you apply some logic to your params before you provide them?
Oct 12, 2021, 6:59 PM
user M
The context is just that I'd like to be able to have a single query. If I provide a document ID as a param, the query would use the provided ID to return that document. If I do not provide a document ID (aka, no params at all) that query would just return all documents of that type.
Oct 12, 2021, 8:28 PM
Right now, I would need to write 2 separate queries, one that expects a param of
$id
, the other that does not.
Oct 12, 2021, 8:28 PM
I mean, where are you performing this query? Is it in the Studio? On a frontend?
Oct 12, 2021, 8:35 PM
Oh, performing the query on an API endpoint in Nextjs, so... frontend... ish?
Oct 12, 2021, 8:37 PM
Got it. So you should be able to perform some JS on the params before you pass them to your client.
const query = id ? `*[_type == 'feed' && _id == $id]` : `*[_type == 'feed']`
const params = id ? { id } : {}

const data = sanityClient.fetch(query, params)

Oct 12, 2021, 8:44 PM
Yeah, that's our approach currently. I suppose there's nothing that can be done within GROQ with params eh? If params are defined in the query, they must be provided, eh?
Oct 12, 2021, 8:46 PM
There's no GROQ conditional to support optional params?
Oct 12, 2021, 8:46 PM
Unfortunately, no conditional params at this time.
Oct 12, 2021, 8:47 PM
Okay, thanks! 🙏
Oct 12, 2021, 8:48 PM
Happy to help!
Oct 12, 2021, 8:48 PM
I think for this specific use case, you can use
coalesce()
to filter by
id
only if
id
is not
null
:

*[_type == 'feed' && id == coalesce($id, id)]
If no
$id
is present, it’ll fall back to
id == id
which always evaluate to
true
.
See an example here:
https://groq.dev/1zBjak9JVZ2ct7eURppBJN
When the parameter
{"userId":2}
is present, it’ll only query todos from that users; otherwise it’ll query everything
Oct 13, 2021, 4:41 AM
I think for this specific use case, you can use
coalesce()
to filter by
id
only if
id
is not
null
:

*[_type == 'feed' && id == coalesce($id, id)]
If no
$id
is present, it’ll fall back to
id == id
which always evaluate to
true
.
See an example here:
https://groq.dev/1zBjak9JVZ2ct7eURppBJN
When the parameter
{"userId":2}
is present, it’ll only query todos from that users; otherwise it’ll query everything
Oct 13, 2021, 4:41 AM
it’s not exactly the same as your string template literal query since
coalesce()
does not falsify value like JS (e.g if id is an empty string it’ll return nothing), so you’d still need some JS magic but at least the query is a little more readable
Oct 13, 2021, 4:50 AM
Thanks
user G
. I actually had tried that in Vision in the Studio and it returns an error stating:
Query error
param $id referenced, but not provided
I'll try it out in code and see if that was a unique case to Vision or not. Thanks for the tip!
Oct 13, 2021, 4:21 PM
ohh I guess groq.js is a little more relaxed with missing params. I wonder if it’d work if you pass in null as the param? If it does, on javascript side, for your function, you can give
null
as the default value for the
_id
Oct 13, 2021, 4:28 PM
ohh I guess groq.js is a little more relaxed with missing params. I wonder if it’d work if you pass in null as the param? If it does, on javascript side, for your function, you can give
null
as the default value for the
_id
Oct 13, 2021, 4:28 PM
I know this is a little bit old but I ran into the same problem and this is what I came up with:
// The simplified query
*[_type == "blogPost" ${categoryId ? optionalCategoryFilter : ''}]
  ${keyword ? optionalKeywordFilter : ''}
  | order(${keyword ? '_score desc,' : ''}_createdAt desc)

optionalCategoryFilter
and
optionalKeywordFilter
is query fragments as plain string.The whole query is a monstrosity but at least it beats having to write multiple different queries to account for the absence of filter parameter.
Jan 19, 2022, 12:57 AM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?