Filtering by array references in Sanity.io

20 replies
Last updated: Apr 7, 2022
Is there a way to filter by elements of an array of references? I have a ProductListing type which references many Products. I want to get all listings that have at least one product in stock. I can’t seem to be able to figure this one out.
I tried a few options along these lines, but it doesn’t seem to work:

*[_type=='ProductListing' && items[]->stock > 0]{
  _id
}
I was looking for something like a
sum
function or any way to filter items without doing a select and filtering client side.I will have more conditions as well based on whether items are currently disabled and such.
AI Update

You're very close! The key issue is understanding how GROQ handles array dereferencing and filtering. Let me break down the correct approach based on the GROQ documentation.

The correct way to filter ProductListings that have at least one product in stock is:

*[_type == 'ProductListing' && count(items[]->[stock > 0]) > 0] {
  _id
}

Here's what's happening step-by-step:

  1. items[] - Gets all items in the array
  2. -> - Dereferences each item (follows the reference to get the actual Product document)
  3. [stock > 0] - Filters the dereferenced products to only those with stock > 0
  4. count(...) - Counts how many products match the condition
  5. > 0 - Checks if at least one product matches

Important: The filter condition goes after the dereference operator (->) and inside brackets. This is crucial because you're filtering the dereferenced documents themselves, not the references.

For multiple conditions (like checking both stock and disabled status):

*[_type == 'ProductListing' && count(items[]->[stock > 0 && !disabled]) > 0] {
  _id
}

You can combine multiple conditions with && or || inside that filter bracket after the dereference.

Alternative using the @ operator (current element):

*[_type == 'ProductListing' && count(items[]->[@.stock > 0]) > 0] {
  _id
}

The @ explicitly refers to the current dereferenced document. While it's optional in simple cases, it can make complex queries clearer.

A practical example with more details:

*[_type == 'ProductListing' && count(items[]->[stock > 0 && !disabled]) > 0] {
  _id,
  title,
  "inStockProducts": items[]->[stock > 0 && !disabled]{
    _id,
    name,
    stock
  }
}

This query not only filters the listings but also returns the actual in-stock products for each listing, which is often useful.

According to the count() function documentation and examples in the query cheat sheet, the pattern you'll use repeatedly is: array[]->[filter conditions], then wrap in count() to check if any exist. This works because GROQ evaluates the dereference first, then applies the filter to those dereferenced documents, then counts the results.

What does this return?

*[_type=='ProductListing']{
  'items': items[]->stock
}
Yes, it’s an array of references
[
  {
    "items": [
      10000000,
      0,
      999998,
      0,
      11
    ]
  }
]
Thanks for confirming. Could you try this?

*[_type=='ProductListing' && count(items[]->stock) > 0]
Thanks for confirming. Could you try this?

*[_type=='ProductListing' && count(items[]->stock) > 0]
*[_type=='ProductListing' && count(items[]->stock) > 0]{
  'items': items[]->stock,
}[0..1]
[ {
“items”: [
10000000,
0,
999998,
0,
11
]
},
{
“items”: [
999
]
}
]
Hm, it could actually be working
let me look through a larger set
{ “items”: [
0
]
}
Found this
I will let it sit till the morning. Let me know if you have ideas on filtering through references on one or more conditions. Perhaps a
score
could work somehow
Yeah, that was bad advice on my part, sorry. I think you may want a join. Just going to test something locally to get the code right.
Something like:

*[_type=='ProductListing']{
  'items': items[]->stock,
}[items[]->stock != 0]

{ “items”: [
0
]
}
Still a few
Is there a way to intersect two arrays? let’s say I would do something like:

items[]._ref in *[filter]._id
Okay, apologies again! I think this may finally capture it:

*[_type == 'ProductListing']{
  'items': items[(@->stock != 0)]->stock,
  _id
}[length(items) > 0]
This requires
v2021-03-25
or later of the API.
Wow. Works like magic. I was able to expand on the filter further with additional conditions! Long live GROQ
Awesome! Glad you got this working! 🙌

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?