GROQ: Query brands with cars having specific color in array of references

16 replies
Last updated: Dec 6, 2023
Hey,
I've a GROQ question. Let's say I have following data and schemas:

• Brands (Car Brands like Audi, Volvo, VW, etc.)
• Cars (Cars like Audi A4, Audi A4, Volvo XC40, VW Golf, etc.)
• Colors (Black, White, Red, Green, etc.)
The Car schema has a reference to
one
brand
and a reference to multiple
colors
(as an array per schema definition), since every car is available in different and multiple colors.

// car.tsx

const carSchema = defineType({
  name: 'car',
  type: 'document',
  title: 'Car',
  //...
  fields: [
    //..
    defineField({
      name: 'brand',
      title: 'Brand',
      type: 'reference',
      readOnly: true,
      to: [{ type: 'brand' }],
    }),
    //..
    defineField({
      name: 'colors',
      title: 'Colors',
      type: 'array',
      of: [
        defineArrayMember({
          type: 'reference',
          to: [{ type: 'colors' }],
        }),
      ],
    }),
    //..
  ],
  preview: {
    //...
  },
})

export default carSchema
Now I want to query for all car brands that have let's say
yellow
cars available, my problem is, that I'm unsure how I can make a condition on a referenced slug.
This GROQ query I made is partially working, but of course it only checks the first color (
color[0]
) for yellow, so I only get brands where the first set color of a car was yellow.
Any way to check all referenced color slugs?


*[_type=="brand" && count(*[_type == "car" && references(^._id) && color[0]->slug.current == "yellow"]) > 0]{
    title,
    "slug": slug.current
}
Current result, but of course there are many missing:

[ { "title": "Audi", "slug": "audi" } ]
Thank you very much.
AI Update

The issue with your query is that you're only checking the first element of the colors array with color[0]->slug.current == "yellow". To check if any color in the array matches "yellow", you need to use array filtering techniques in GROQ.

Here's the corrected query:

*[_type=="brand" && count(*[_type == "car" && references(^._id) && "yellow" in colors[]->slug.current]) > 0]{
    title,
    "slug": slug.current
}

The key change is "yellow" in colors[]->slug.current. Here's what's happening:

  • colors[] - This expands the array of color references
  • ->slug.current - This dereferences each color and gets its slug
  • "yellow" in colors[]->slug.current - This checks if "yellow" exists anywhere in the resulting array of slugs

Alternative approach using array filtering:

You can also use array filtering with the @ operator for more explicit filtering:

*[_type=="brand" && count(*[_type == "car" && references(^._id) && count(colors[@->slug.current == "yellow"]) > 0]) > 0]{
    title,
    "slug": slug.current
}

This works by:

  • colors[@->slug.current == "yellow"] - Filters the colors array to only include references where the slug is "yellow"
  • count(...) > 0 - Checks if at least one color matched

Both approaches will find all brands that have at least one car available in yellow, regardless of where yellow appears in the colors array.

The first approach ("yellow" in colors[]->slug.current) is generally more concise and readable for simple equality checks like yours. This should give you all the brands (Audi, Volvo, VW, etc.) that have at least one car model available in yellow!

Show original thread
16 replies
user B
Sanity oficial Groq cheatset has an example on how to that, you could try something similar to:

&& "yellow" in color[].slug.current]

See more at the oficial docs here: https://www.sanity.io/docs/query-cheat-sheet
wow now that was fast, thank you I'll take a look
user T
thank you, the thing is, with this query I get zero results, so
[]


*[_type=="brand" && count(*[_type == "car" && references(^._id) && "yellow" in colors[].slug.current]) > 0]{
    title,
    "slug": slug.current
}
And with this I get at least one result, where I know the first color of an Audi is yellow:


*[_type=="brand" && count(*[_type == "car" && references(^._id) && colors[0]->slug.current == "yellow"]) > 0]{
     title,
    "slug": slug.current
}
If I combine them, just for a test, I still get, as expected my one Audi result:


*[_type=="brand" && count(*[_type == "car" && references(^._id) && colors[0]->slug.current == "yellow" || "yellow" in colors[].slug.current]) > 0]{
     title,
    "slug": slug.current
}
Can there something else be wrong? With the schema?
I think you can simplify your query. Brands are related to cars, so first get all the cards, then filter the cards by color, then return the distinct brands.
Color is a sub field of cars, not of an specific brand.
You are right I can sure flatten the query down and get all cars, and then their brands, but it's the same problem:

// work, it's basically the same as the querys above
*[_type=="car" && colors[0]->slug.current == "yellow"]

// does not work
*[_type=="car" && "yellow" in colors[].slug.current]
*[_type=="car" && "yellow" in colors[]->slug.current]
*[_type == "car" && count((colors[]->slug.current)[@ in ["yellow"]]) > 0)

*[_type=="car" && count((colors[]->slug.current)[@ in ["yellow"]]) > 0]
Trying to find an example for tyour use case, but something like this should work. You’d have to apply a
dinstinct
or unique filter to make sure brands woulnd’t be repeated
In situations like this,
<http://sanity.io|sanity.io>
cheatset is your best friend. https://www.sanity.io/docs/query-cheat-sheet
Lucas you got it right
Glad it worked 🙂
Have a look at the cheatset and you see special symbols in groq syntax like
@
that are quite useful when querying references 🙂
Wow
user T
it really works this way, thank you vey much, I'll take a look to understand why
It also works with the brands query now, combined with the cars, so the brands are unique there 🙂
Nice! Well done 🙂

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?