Get unique years from datetime field in Sanity GROQ query

16 replies
Last updated: Dec 1, 2025
Is it possible to get unique years value only from date time field across all documents of certain type? I have this query
{"uniqueYears": array::unique(

*[_type in ["event", "exhibition"] && defined(endDate)][].endDate

)}
but it returns the unique full dates.

0:"2018-01-06T12:30:00.000Z"

1:"2018-01-13T08:00:00.000Z"
Tried adding
| split("-")[0]
in the end of the query, but it’s not supported.
AI Update

Yes! You can extract unique years from datetime fields in GROQ. The key is to convert the datetime to a string first, then use string::split() to extract the year portion. Here's the working solution:

{
  "uniqueYears": array::unique(
    *[_type in ["event", "exhibition"] && defined(endDate)]
      .endDate
  ) | [string::split(string(@), "-")[0]]
}

How this works:

  1. The filter *[_type in ["event", "exhibition"] && defined(endDate)] gets your documents
  2. .endDate extracts just the endDate values from each document
  3. array::unique() removes duplicate datetime values
  4. The pipe operator | passes the unique datetimes to the next operation
  5. The projection [...] applies a transformation to each element in the array
  6. string() function converts each datetime to a string in RFC3339 format (like "2018-01-06T12:30:00.000Z")
  7. string::split(string(@), "-") breaks the string at each "-" character, creating an array like ["2018", "01", "06T12:30:00.000Z"]
  8. [0] grabs just the first element (the year)

This will give you:

{
  "uniqueYears": ["2018", "2019", "2020"]
}

Alternative approach - You can also apply the transformation before uniquifying:

{
  "uniqueYears": array::unique(
    *[_type in ["event", "exhibition"] && defined(endDate)]
      .[string::split(string(endDate), "-")[0]]
  )
}

Why your original approach didn't work:

  1. The split() function needs the string:: namespace prefix in GROQ
  2. It only works on strings, so your datetime endDate field needs to be converted first using string()
  3. The syntax for applying transformations across arrays requires proper use of projections with []

The years will be returned as strings. If you need them as numbers for sorting or comparison, you'd need to handle that conversion in your application code since GROQ doesn't have a built-in string-to-number conversion function.

Show original thread
16 replies

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?