πŸ‘€ Our most exciting product launch yet πŸš€ Join us May 8th for Sanity Connect

Matching the end of a string in GROQ

By Geoff Ball

GROQ doesn't yet include a function to match the end of a string, but we can simulate it by splitting our string on our term.

GROQ query

// GROQ filter
*[
  string::split(@[$field], $term)[-1] == ""
]

// GROQ params
{
  "field": "title",
  "term": "vegetables"
}

GROQ provides a startsWith function to match the start of a string, but doesn't yet include a function to match the end of a string. (Note: There is a match operator, but it tokenizes and doesn't let you match patterns that include non-alphanumeric values).

There is another string function, split, that we can use to model the functionality a function like string::endsWith() might provide. The split function takes a string, splits it on a separator, and returns an array of strings. The documentation provides some common use cases, such as splitting on a space to return an array of words from a sentence. By splitting on the term we want to match, we can take advantage of two features of that function:

  1. It works globally (matches all instances) in the string, which means we won't be tripped up when there are multiple instances of the term in the field, and
  2. When it encounters a value that doesn't contain the search term, the function returns the entire string as its first (and last) value. This is what enables us to check for equality of that last term against the empty string. (As an aside, we also benefit from the fact that Sanity unsets an empty value (i.e., removes it) rather than storing empty strings as values. We don't need to check if the field is an empty string, because if it were it would simply be undefined, leaving no string to split.)

Essentially, we're splitting the string anywhere it finds the term, then returning an array of strings containing what comes before and after those terms. If the final term of the array ([-1]) is an empty string, it means the separator must have been at the end of the string.

In its simplest form, we could add something like the following to our GROQ query (within the filter):

string::split(title, "radish")[-1] == ""

That won't tokenize like the match operator, meaning it won't inadvertently match "I am eating a radish." with a period at the end. (Want to match radish. with a period? Include a period in the separator, which is the second term of the function.) What it will match is "A radish is a radish", or "don't shorten traditional to tradish", or "roast beef needs horseradish". To match a complete term at the end of the string, prepend it with a space.

string::split(title, " radish")[-1] == ""

The final example here refactors your string and search term into the params of your GROQ query (as field and term), making it much more reusable throughout your code base. @[$field] might look a bit unusual, but it works out to @['title'] (or, if you like to think in terms of dot notation, @.title, where @ is the current scope).

Contributor

Other schemas by author