GROQ: Finding shared references between documents (referencedBy workaround)

10 replies
Last updated: Jan 28, 2026
This isn't a question but a candid, open experiment that appears to have worked well.
GROQ has a
*references() * function but I wasn't aware of a referencedBy analogue to take advantage of the references being bidirectional.
I needed to determine the referenced documents of one type that two other documents of another identical type
share. In this case, two "weddings" having their list of "vendor" documents compared.
While my desired magic function doesn't seem to exist, I have seen clever approaches like
this and adapted it, so that it works in the one case I need it where

*[ _type == "vendor"]{
  _id,
  vendorName,
  "one":  count(*[_id==$weddingId1 && references(^._id)]),
  "two" : count(*[_id==$weddingId2 && references(^._id)])
}[one > 0 && two > 0].vendorName
and the params

{
  "weddingId1":"8bdbe960-3f74-45b9-9b8e-6269a2cae8e4",
  "weddingId2":"d83030c5-383a-4137-8385-4d305c3f3212"
  
}
give me, in Vision,

"result":[ 1 item
0:"Copper Rose"
]
The pivotal aspect is that the projection can be filtered, and even though I am used to always seeing numbers in those square brackets, it
is a filter and therefore permits some logic, just as a JavaScript filter might. Which is to say, "whatever passes this test goes through."
Part of the fun of GROQ though is practicing to where the syntax and concepts finally mesh in your head.

Once I had a feel that I was really targeting things, the
infinitely more clean, clear and elegant query below produces the same result:

*[
  _id in *[_id == $weddingId1].vendorList[]->_id &&
  _id in *[_id == $weddingId2].vendorList[]->_id
 ].vendorName
AI Update

This is a great share! You've discovered some really elegant GROQ patterns for finding shared references between documents, and your journey from the first working solution to the cleaner final query is a perfect example of how GROQ proficiency develops.

Your key insights are spot-on:

1. Filters accept logical expressions: You're absolutely right that the square bracket notation [condition] is a filter that can contain any boolean logic, not just array indices. This is fundamental to GROQ's power and opens up possibilities like your [one > 0 && two > 0] approach.

2. The parent reference (^) trick: Your first solution cleverly uses the parent operator ^ to reference the vendor document from within the nested query. This pattern of counting references from the "wrong direction" is a well-known GROQ workaround for the lack of a native referencedBy() function.

3. The cleaner _id in pattern: Your final query is indeed much more readable:

*[
  _id in *[_id == $weddingId1].vendorList[]->_id &&
  _id in *[_id == $weddingId2].vendorList[]->_id
].vendorName

This directly expresses the intent: "find vendors whose IDs appear in both wedding vendor lists." The _id in operator combined with dereferencing (->) makes it very declarative.

Potential optimizations to consider:

If you find yourself doing this frequently or with many weddings, you could also use the count() approach inline:

*[_type == "vendor" && count(*[_id in [$weddingId1, $weddingId2] && references(^._id)]) == 2].vendorName

This checks that exactly 2 of your specified weddings reference each vendor, which scales better if you're comparing more than two documents.

Thanks for sharing this exploration—it's exactly the kind of problem-solving that helps others learn GROQ's more advanced patterns! The progression from "it works" to "it's elegant" is where GROQ really clicks.

Show original thread
10 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?