Query documents by tag references with dynamic ordering in Sanity

40 replies
Last updated: Oct 11, 2022
Dear Sanity team 👋
I am having trouble with this query and am happy if you can point me into the right direction.
I want to get specific documents which have a reference to specific tags ordered by publishedAt descending or ascending.


`*[_type in $documentTypes 
    && count((tags[]->tag.current)[@ in $referenceTags]) > 0] 
   | order($orderBy) 
   {
      "type": _type,
      publishedAt, 
      title, 
      "tags": tags[]->label
    }`

AI Update

The issue with your query is that you cannot pass the order expression itself as a parameter like order($orderBy). GROQ doesn't support dynamic ordering expressions through parameters in this way.

According to the order() function documentation, while you can pass document types and reference tags as parameters to GROQ queries, passing the order expression itself as a parameter (e.g., $orderBy containing "publishedAt desc") doesn't work as expected.

Solutions

Build separate queries based on your ordering needs:

// In your application code
const orderClause = ascending ? 'publishedAt asc' : 'publishedAt desc';

const query = ascending 
  ? `*[_type in $documentTypes 
      && count((tags[]->tag.current)[@ in $referenceTags]) > 0] 
     | order(publishedAt asc) 
     {
        "type": _type,
        publishedAt, 
        title, 
        "tags": tags[]->label
      }`
  : `*[_type in $documentTypes 
      && count((tags[]->tag.current)[@ in $referenceTags]) > 0] 
     | order(publishedAt desc) 
     {
        "type": _type,
        publishedAt, 
        title, 
        "tags": tags[]->label
      }`;

const results = await client.fetch(query, { documentTypes, referenceTags });

Option 2: Sort Client-Side

Fetch the results without ordering and sort them in your application:

const query = `*[_type in $documentTypes 
    && count((tags[]->tag.current)[@ in $referenceTags]) > 0] 
   {
      "type": _type,
      publishedAt, 
      title, 
      "tags": tags[]->label
    }`;

const results = await client.fetch(query, { documentTypes, referenceTags });

// Sort in JavaScript
results.sort((a, b) => {
  const dateA = new Date(a.publishedAt);
  const dateB = new Date(b.publishedAt);
  return ascending ? dateA - dateB : dateB - dateA;
});

Option 3: Template Literal Approach

If you're comfortable with it, you can use template literals to construct the query dynamically:

const orderDirection = ascending ? 'asc' : 'desc';

const query = `*[_type in $documentTypes 
    && count((tags[]->tag.current)[@ in $referenceTags]) > 0] 
   | order(publishedAt ${orderDirection}) 
   {
      "type": _type,
      publishedAt, 
      title, 
      "tags": tags[]->label
    }`;

const results = await client.fetch(query, { documentTypes, referenceTags });

Option 1 or 3 is the most straightforward approach and maintains server-side sorting performance, which is especially important for larger datasets. Option 2 works well if you have a small result set or need more complex sorting logic that's easier to express in JavaScript.

Show original thread
40 replies
I am passing
$documentTypes
and
$referenceTags
as well as
$orderBy
as a params to the querywhere the
$documentTypes
and
$referenceTags
are arrays of strings like ["post", "video"] and ["tag1", "tag2"]and
$orderBy
a string of either
publishedAt desc
or
publishedAt asc

The correct documents with the correct reference tags are returned.

However, the order is always wrong.

Is it maybe not possible to pass the value for "order" as a param to the query?
🤔
Or do I need to order first and then filter by tags?
Could you share your documenType schema please?
Hey there. What’s not working? Are you not getting the right documents? Or is the sorting not working?
Hey
user F
Thanks for your reply and sorry for the late answer.

I am still having the same problem
😢
The sorting is not working. That is the main issue.
The correct documents with the correct reference tags are returnedbut the sorting is always wrong

I can not even tell which sorting is returned
but definitely not sorted by the published date
user F
What am I doing wrong?Thanks for your help again.
user F

Just pinging you again to show that I am really here.
Sorry that my last answer took so long.
😅
I am happy if you can find the time
for my code above and the issue with the wrong sorting.
Hellooooo. I unfortunately don't have time today, I'm very sorry. 😞
Alright! Thanks for the information.
Hi
user F
Maybe it fits in today?
🙂
I'll try but not sure. 😞
It's just that the order doesn't work in the query above.
Thanks!
Thanks
user F

I am posting this again in the main channel. Maybe someone else has time?
Hi User. I’m not sure if query params can be used in the
order()
function. Can you confirm that hardcoding something works as intended? Can you then try using string template literals instead to see if that works?
Hi
user A

Thanks so much for your reply!

Yes, hard coding the order works.

Problem is I am having a select with which the user can decide the order of the query results (oldest first, latest first, A-Z, Z-A ....)

How can I then dynamically pass these orderBy values to the query?
Were you able to try using template literals?
Thanks.
In my eyes this whole query is already a template literal


`*[_type in $documentTypes 
    && count((tags[]->tag.current)[@ in $referenceTags]) > 0] 
   | order($orderBy)` 

Maybe I am getting the definition of a template literal wrong?
Sorry, I don’t want to introduce confusion. No argument from me about what you just posted.
Specifically,
$orderBy
is a GROQ parameter. Can you instead try
${orderBy}
?
I mainly want to rule out what’s not possible before bringing it to the team internally to consider options.
Ah, now I see
Yes, this works too.
Okay, that’s good to hear. Thanks for confirming.
I have a feeling that parameters aren’t going to work in the
order()
function, and that this is the route you’ll need to take.
Ah I see. Thanks!
So in sum: Passing a Groq param to
order
is not working.
If I need to pass the value as
${orderBy}
then I'll need to rewrite my whole query setup
as these are currently defined in a re-usable object.
Given what you’ve posted above, that’s the way it seems. I’ll still try to confirm internally.
Thanks 🙏
Hi User. Thanks for your patience on this. Confirmed that a param can’t be passed into
order()
.
(See follow-up.)
Thanks for all your help and explanations
user A
Hi User. You’re welcome, though before you get too far refactoring, it turns out what I said wasn’t the case.

order($orderBy)
will try to sort by the literal string value of
$orderBy
, which is why it doesn’t work. However, one of our engineers just let us know that
order(@[$orderBy])
should in fact work how you’re wanting.
Hopefully that makes your refactor easier, as it’s more in line with what you were originally trying. Let us know how it goes. We’ll also work on adding it to the docs.
Hi
user A

Thanks for the update!

I tried


`*[_type in $documentTypes 
    && count((tags[]->tag.current)[@ in $referenceTags]) > 0] 
   | order(@[$orderBy]) 
   {
      "type": _type,
      publishedAt, 
      title, 
      "tags": tags[]->label
    }`
with param
$orderBy: "publishedAt desc"but it doesn't work.

The response is a 400 with

{"error":{"description":"Name contains invalid characters","type":"validationError"}}

When I remove
order(@[$orderBy])
it works again.
When you define your params, you won’t want the
$
to be there. Only in the query.
Yes, sure. Sorry for the confusion.
It´s orderBy
Bit still the same error 😄
The space between
publishedAt
and
desc
is throwing that error. I’m not sure there’s a way to specify the order direction dynamically here so
desc
or
asc
might need to be hard-coded (with
$orderBy
changed to just
publishedAt
).
Oh that's interesting!Thanks again for checking it out yourself
🌟
I need to have it dynamically as I'll pass these params from a user´s input select:

• "publishedAt desc",
• "publishedAt asc",
• "lower(title) desc",
• "lower(title) asc",
I refactored the queries now completelyand generate the groq queries dynamically with template literals

I general it would be more elegant to have it work with groq params as I am having other queries which do work like that before.

But if this is not possible with dynamic orderBy values
then I would stick with the refactored solution then.

Still I would like to know if you updated the docs
🙂
I would like to know if you updated the docs
Not yet. Waiting to hear back internally about passing a direction dynamically.

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.

Was this answer helpful?