GROQ: Fetch documents by category excluding latest 8 documents

17 replies
Last updated: Sep 27, 2021
Hello,
I want to fetch some documents that contains "dance" as category. But the documents should not be one of the latest 8 documents. How can I do this in GROQ?
AI Update

You can achieve this by combining filtering, ordering, and slicing in GROQ. Here's how to fetch documents with "dance" as a category while excluding the latest 8 documents:

*[_type == "yourDocumentType" && category == "dance"] 
  | order(_createdAt desc) [8..]

Let me break this down:

  1. *[_type == "yourDocumentType" && category == "dance"] - Filters documents to only those with "dance" as the category
  2. | order(_createdAt desc) - Sorts all matching documents by creation date, newest first (you could also use _updatedAt or any other date field)
  3. [8..] - Slices the array starting from index 8 to the end, effectively skipping the first 8 (latest) documents

The key here is the slice component syntax. Using [8..] means "start at index 8 and include everything after that." Since arrays are zero-indexed, this skips indices 0-7 (the 8 most recent documents).

If you want to also limit the total number of results, you can extend the slice:

*[_type == "yourDocumentType" && category == "dance"] 
  | order(_createdAt desc) [8..17]

This would give you documents 9-18 (skipping the latest 8, then returning the next 10).

Important note: Make sure to replace _createdAt with whatever date field makes sense for determining "latest" in your use case - it could be a custom publishedAt field or _updatedAt depending on your content model.

Show original thread
17 replies
*[category match 'dance'] | order(date asc)[0...-8]
The filter matches
dance
, then those documents are sorted by date in ascending order (oldest first), and finally, all but the last eight documents are returned.
Alternatively, you could do:


*[category match 'dance'] | order(date desc)[8..-1]
That sorts in descending order and returns from the 9th document (index 8 in a zero-index count) to the last one. Notice this uses two dots instead of three.
the first 8 will have dance music and many other categories
*[category match 'dance'] | order(date asc)[0...-8]
The filter matches
dance
, then those documents are sorted by date in ascending order (oldest first), and finally, all but the last eight documents are returned.
Alternatively, you could do:


*[category match 'dance'] | order(date desc)[8..-1]
That sorts in descending order and returns from the 9th document (index 8 in a zero-index count) to the last one. Notice this uses two dots instead of three.
If I'm matching dance and saying 8..-1, Sanity will avoid the first 8 documents with "dance" category right?
the first 8 will have dance music and many other categories
Maybe you’re after this then?

*[] | order(date asc)[0...-8][category match 'dance']

If I’m matching dance and saying 8..-1, Sanity will avoid the first 8 documents with “dance” category right?
In the first examples I posted, yes. If you just want the
dance
documents from all documents that aren’t in the last eight (of all documents), you could try the query above.
I'll show the query
The query I use to fetch first 8

*[_type == "post"&& featured != true] | order(publishedAt desc) {_id}[0...8]
The query I use to get a specific category items

*[_type == 'post' && *[_type == "category" && featured != true && slug.current == "${cat}"][0]._id in categories[]._ref] | order(publishedAt desc) {_id}[0...${count}]
Actually I'm trying to get blogs in specific categories, but they should not be included in the latest 8 documents
You want the first half of your category query to be the same as your first 8 query, and then do something similar to what Geoff suggested:

*[_type == "post" && featured != true] | order(publishedAt desc) [8..-1][references("catId")] { _id }
An example:
https://groq.dev/KCY0kE1tA2rNLI7cDcdECC
You want the first half of your category query to be the same as your first 8 query, and then do something similar to what Geoff suggested:

*[_type == "post" && featured != true] | order(publishedAt desc) [8..-1][references("catId")] { _id }
An example:
https://groq.dev/KCY0kE1tA2rNLI7cDcdECC
Hi
user G
, I my requirement is that the first 8 documents should not appear in any other query
yes, if you do [8..-1] then they should not? You can modify the query I share in the groq playground to be similar to your first query:
*[_type == "post" && featured != true] | order(publishedAt desc) [0...8]
& you’ll see that they don’t overlap
is there any way to reference slug instead of catId?
is there any way to reference slug instead of catId?
the post references one or more categories as an array
Yeah I think so, you’d need to query for the
_id
from inside the
references()
function:
*[_type == "post"] | order(order desc) [2..-1] [references(*[_type == "cat" && title == 'Cat 1'][0]._id)]
We resolved this issue in DM — the query above worked!

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?