Fetching random documents using queries in Sanity.io

4 replies
Last updated: Aug 22, 2024
Hi all! anyone with tips for how to get random documents in a query? or a work around for it? I guess I could write in random numbers in a field on a cron job or something, but would be nice to see if its any better approaches. Seems its not directly supported in the API.
AI Update

You're right that GROQ doesn't currently support random sorting directly! This is a feature that's been requested since 2019 and is still being considered by the Sanity team. Here are the workarounds available:

Client-Side Shuffling

The most common approach is to fetch your documents and shuffle them client-side:

*[_type == "post"]

Then use JavaScript to shuffle the results:

const shuffled = results.sort(() => 0.5 - Math.random()).slice(0, 10);

This works but means fetching more data than you need, which isn't ideal for performance.

Random Field with Cron Job

Your instinct about using a random field is actually a solid workaround! Add a randomOrder field to your documents and update it periodically:

// In your document schema
{
  name: 'randomOrder',
  type: 'number',
  hidden: true
}

Then query with:

*[_type == "post"] | order(randomOrder asc)[0..9]

You can update these values with a cron job or Sanity Function that runs periodically. This gives you cacheable "random" results that change on your schedule.

Random Index Technique

A more sophisticated approach mentioned in the GitHub discussion is to store a random index (0-1) in each document, then generate a random number client-side and fetch documents with indices greater than that number:

*[_type == "post" && randomIndex > $randomNumber] | order(randomIndex asc)[0..5]

This reduces the data transferred but still requires some client-side randomness.

Why No Native Support?

The main challenge is caching. Random queries are essentially uncacheable, which would hurt performance at scale. One proposed solution is a seed parameter where the same seed always returns the same "random" order, allowing caching while still providing variability.

The Sanity team has acknowledged this feature request and is considering it, but there's no timeline yet. Your cron job approach is probably the most practical solution for now!

In two queries you could do it like this:

const total = await client.fetch("count(*)")

const randomIndex = Math.floor(Math.random() * (total + 1))

const random = await client.fetch("*[$randomIndex]", {randomIndex})
Ok, thanks. That code is a bit new for me, if its random by some specific types for instance “doc”, would it be like this then?

const total = await client.fetch("count(*[_type == 'doc')")

const randomIndex = Math.floor(Math.random() * (total + 1))

const random = await client.fetch("*[$randomIndex]", {randomIndex})
Close:

const total = await client.fetch("count(*[_type == 'doc'])")

const randomIndex = Math.floor(Math.random() * (total + 1))

const random = await client.fetch("*[_type == 'doc'][$randomIndex]", {randomIndex})

thanks a lot:)

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?