How to structure content in Sanity.io & use GROQ queries for filtering & referencing related documents.
19 replies
Last updated: Feb 23, 2023
V
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
V
i see! so, if i want to adapt this example with my content, do you have an idea of how it would be?
V
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},
}
},
},
},
],
},
],
}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:
But if you want to do the array of references then you actually need a dynamic filter using
https://www.sanity.io/docs/reference-type#8118f73f6758
*[_type == "director"]{
...,
*[_type == "film" && references(^._id)][0..2] | order(date desc)
}^.to reference the parent document:
https://www.sanity.io/docs/reference-type#8118f73f6758
S
In addition you could also create a pane with document lists in there , which use the query
And the lists would be in sync with your content and would not need to be kept up to date
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
V
user J
oh waouw! i did not know about this. i’ll give this a try. do you think it may cover my needs?V
thank you for the answers everybody 🙂
V
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:
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
of: [
{
type: 'reference',
to: [{type: 'films'}],
options: {
filter: 'director.name == $directorName',
filterParams: {directorName: '^.name'},
},
},
],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
V
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' }
}
},
],V
i can achieve this by putting manually a director id instead of the param, but now i need to retrieve the document id automatically
S
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!
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!
V
i see! does your last sentence refer to the sanity-pane solution, or is it an other way of doing it?
S
You can add a custom desk structur e like this:
You can follow
this guide here if you want
// 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' }])
)this guide here if you want
V
oh great! alright, this is a lot of resources and help you provided me. i cannot thank you enough!
V
you rock!
S
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
S
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:
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.