👀 Our most exciting product launch yet 🚀 Join us May 8th for Sanity Connect

How to structure content in Sanity.io & use GROQ queries for filtering & referencing related documents.

19 replies
Last updated: Feb 23, 2023
hi. i’m struggling a lot with something: i have a Films document type that references one Director (which is an other document type). in a Director page, i want a field named “relatedFilms” which is an array of references to Films, but i’d like to only be able to choose films that reference the current Director
Feb 23, 2023, 11:45 AM
i see! so, if i want to adapt this example with my content, do you have an idea of how it would be?
Feb 23, 2023, 1:40 PM
here is how my schema looks, but in my Sanity desk, the search query returns no result for “”
import {RiUserLine as icon} from 'react-icons/ri'

export default {
  title: 'Directors',
  name: 'directors',
  type: 'document',
  icon,
  fields: [
    {
      title: 'Name',
      name: 'name',
      type: 'string',
    },
    {
      title: 'Slug',
      name: 'slug',
      type: 'slug',
      description: 'Click on *Generate* to create the slug',
      options: {
        source: 'name',
        slugify: (input) => input.toLowerCase().replace(/\s+/g, '-').slice(0, 200),
      },
    },
    {
      title: 'Related Films',
      name: 'relatedFilms',
      type: 'array',
      description: "Reference the director's films you want to showcase",
      of: [
        {
          type: 'reference',
          to: [{type: 'films'}],
          options: {
            filter: ({document}) => {
              return {
                filter: 'director == $director',
                params: {director: document.name},
              }
            },
          },
        },
      ],
    },
  ],
}
Feb 23, 2023, 1:45 PM
Rather than create a two-way reference it might cause less headaches longterm to just find the latest 3 films by that director in a GROQ request which would look like:

*[_type == "director"]{
  ...,
  *[_type == "film" && references(^._id)][0..2] | order(date desc)
}
But if you want to do the array of references then you actually need a dynamic filter using
^.
to reference the parent document:


https://www.sanity.io/docs/reference-type#8118f73f6758
Feb 23, 2023, 1:47 PM
I think that’s all correct but I’ve got go eat lunch 🙂
Feb 23, 2023, 1:48 PM
In addition you could also create a pane with document lists in there , which use the query
user P
posted before. This way you leverage the references instead of creating bilateral references, which are not needed 🙂
And the lists would be in sync with your content and would not need to be kept up to date
Feb 23, 2023, 4:20 PM
user J
oh waouw! i did not know about this. i’ll give this a try. do you think it may cover my needs?
Feb 23, 2023, 4:50 PM
thank you for the answers everybody 🙂
Feb 23, 2023, 4:50 PM
alright so for now i just tried to do the array of reference as i intended, in the first place, with this piece of code:

of: [
        {
          type: 'reference',
          to: [{type: 'films'}],
          options: {
            filter: 'director.name == $directorName',
            filterParams: {directorName: '^.name'},
          },
        },
      ],
but it does not return any result for now.. though in my API, each film should have a director field, with a name property inside.

is it correlated with the fact that when i inspect my API response of a film, the director field does not contain any data but a _ref and and _type? which is odd, because there is
Feb 23, 2023, 5:43 PM
okay i have the feeling i’m getting close to it!
of: [
        {
          type: 'reference',
          to: [{type: 'films'}],
          options: {
            filter: 'director._ref == $directorId',
            filterParams: { directorId: '^._id' }
          }
        },
      ],
Feb 23, 2023, 6:00 PM
i can achieve this by putting manually a director id instead of the param, but now i need to retrieve the document id automatically
Feb 23, 2023, 6:00 PM
As said before you should not do it like that 😊When you think about it the structure is:
you have directors and films. each film has a director it references. On the director doc you add a pane where you groq all the films, that reference the director.

Adding 2 way references will make your data structure very cumbersome in the end. This is why loading the references dynamically in a list like this is better!
In addition you can set up a custom structure, where you filter the films to their refrerenced directors. You do not need the array!
Feb 23, 2023, 6:03 PM
i see! does your last sentence refer to the sanity-pane solution, or is it an other way of doing it?
Feb 23, 2023, 6:08 PM
You can add a custom desk structur e like this:
// structure
S.listItem()
      .title('Films')
      .schemaType('film')
      .child(
        S.documentList()
          .title('Film by Director')
          .filter('_type == "director"')
          .child(
            (directorId) =>
              S.documentList()
                .title('Films')
                .filter('_type == "film" && director._ref == $directorId')
                .params({ directorId })
                .menuItems(S.documentTypeList('film').getMenuItems())
                .canHandleIntent(
                  S.documentTypeList('film').getCanHandleIntent()
                )
          )
          .defaultOrdering([{ field: 'title', direction: 'asc' }])
      )
You can follow
this guide here if you want
Feb 23, 2023, 6:08 PM
oh great! alright, this is a lot of resources and help you provided me. i cannot thank you enough!
Feb 23, 2023, 6:10 PM
you rock!
Feb 23, 2023, 6:10 PM
Happy I could help! And I would recommend looking into our structured content ressources and maybe asking some question about the overall structure in content-strategy
Feb 23, 2023, 6:12 PM
You will see, you will unlock MASSIVE possibilities when you learn how to think in structured content :) Also this might help you as it helped me understand the power of GROQ :groq:
Feb 23, 2023, 6:13 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?