GROQ Query - Is it Possible to Filter Variants?

1 replies
Last updated: May 16, 2021
Hi, I am hoping that someone can help me with understanding this. I have a groq query that works in v1 of the API, but nothing subsequent (e.g. 2021-03-25). I have a document type "product" that has an array of references. I am trying to filter that array so that the referenced variants are in a parameter, like below:
*[_type == "product" && _id in $ids]
      {
        price,
        "variant": variants[]->|[variantId in $variantIds][0]{
        	packageSize, 
        	flavour,
          variantId,
      	},
        "image": images|[defaultImage == true][0]{
          altText,
          "url": asset->url
        }
      }
This is giving an error now at the
[variantId in $variantIds]
that an object or function is expected. I have tried various other ways of structuring this and the best I can get is returning an array of objects where only one has content... any help appreciated
AI Update

I can see the issue! The problem is with how you're chaining your filter operations after dereferencing. The pipe operator | expects an object or function (like order() or a projection), but you're trying to use a filter [variantId in $variantIds] directly after it.

The syntax variants[]->|[variantId in $variantIds] is invalid because after the pipe operator, GROQ expects a projection {} or a function like order(), not a filter [].

Here's the corrected syntax:

*[_type == "product" && _id in $ids]
{
  price,
  "variant": variants[]->[variantId in $variantIds][0]{
    packageSize, 
    flavour,
    variantId,
  },
  "image": images[defaultImage == true][0]{
    altText,
    "url": asset->url
  }
}

Key changes:

  1. Remove the pipe operator | between -> and the filter
  2. The syntax is: variants[]-> (dereference all) then [variantId in $variantIds] (filter) then [0] (take first) then {...} (project)

Why this works:

According to the GROQ pipeline components documentation, filters use [] syntax and can be chained directly without the pipe operator. The pipe operator is specifically required for certain operations like order() and is optional for projections, but filters must be adjacent to the array they're operating on.

The sequence is:

  • variants[] - get all variants array elements
  • -> - dereference each variant reference
  • [variantId in $variantIds] - filter the dereferenced variants
  • [0] - take the first match
  • {...} - project the fields you want

This syntax change should work across all API versions from 2021-03-25 onwards. The v1 API was more lenient with syntax, which is why your original query worked there but fails in later versions.

Ok, after the weekend to form a new mind, I have come up with this:
"variant": variants[@->variantId in $variantIds]->{
          packageSize,
        	flavour,
        	variantId
        }
which does the trick

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?