How to Filter out Existing References & Add a Default Reference in Schema
22 replies
Last updated: Sep 27, 2021
C
2 questions regarding an array of references:
1. Is there an easy way to filter out any already references already added to the parent array from the list of available array references in the default dialog dropdown? Should this potentially be default behavior (or a setting)?
2. I'm trying to reference a default author for my post document type, but since its an array of a reference, I'm not quite sure how to nest it.
This is my current attempt that is not working:
1. Is there an easy way to filter out any already references already added to the parent array from the list of available array references in the default dialog dropdown? Should this potentially be default behavior (or a setting)?
2. I'm trying to reference a default author for my post document type, but since its an array of a reference, I'm not quite sure how to nest it.
This is my current attempt that is not working:
// post.js export default { ... { name: 'authors', title: 'Authors', type: 'array', initialValue: { _type: 'reference', to: { _type: 'person', _ref: params.'9122a1cc-40d0-4120-9f30-3e997007896c' } }, }, ... }
Sep 27, 2021, 5:42 PM
For question 1, you'll want to use the
There's more on setting up dynamic filters
here .
With your initial value, is it a
parameterized template or just a static predefined author reference you're looking to use?
unique()validation rule. There's also the
filteroption, which in your case would look something like this:
options: { filter: ({ document }) => { const existingAuthors = document.authors.map(author => author._ref).filter(Boolean) return { filter: '!(_id in $existingAuthors)', params: { existingAuthors } } } }
here .
With your initial value, is it a
parameterized template or just a static predefined author reference you're looking to use?
Sep 27, 2021, 5:55 PM
Oh, and that filter option goes on your authors array, sorry didn't make that clear in the original method.
Sep 27, 2021, 5:56 PM
C
No worries, I thought that made sense.
Regarding the
Filtering selected elements out of the reference array:I've added the validation rule and the options with some changes based on the array object, although the filter doesn't seem to be working correctly (the validation rule is though).
Expected state: What I'd expect to see in this case is that once I've added one project to my array of references that its no longer available in the selection options.
Observable state: projects that have been previously added are still visible among list of options, and return an error once added again
Here's this document's code:
Do I need to change the document filter to specifically reference the projects array?
Regarding the
Filtering selected elements out of the reference array:I've added the validation rule and the options with some changes based on the array object, although the filter doesn't seem to be working correctly (the validation rule is though).
Expected state: What I'd expect to see in this case is that once I've added one project to my array of references that its no longer available in the selection options.
Observable state: projects that have been previously added are still visible among list of options, and return an error once added again
Here's this document's code:
//recommendation.js export default { title: 'Recommendation', name: 'recommendation', type: 'document', fields: [ ... { title: 'Projects', name: 'projects', type: 'array', of: [ { title: 'Related Projects', type: 'reference', to: {type: 'sampleProject'} } ], validation: Rule => Rule.unique(), options: { filter: ({document}) => { const existingProjects = document.projects.map(project => project._ref).filter(Boolean) return { fitlers: '!(_id in $existingprojects)', params: { existingProjects } } } } } ... }
Sep 27, 2021, 6:28 PM
C
Regarding the set an initial value of a referenced author array, I don't think its a parameterized template. I just want to reference a single person among my person's document as the default author, with no changes to the persons document itself, and no new persons added as initial values as well
Sep 27, 2021, 6:31 PM
Ah, yes the validation option won't remove the option from the list, just throw an error when you do select it. That's why sometimes I prefer to just filter the list so that it's not even an option. And I was wrong when I said the filter goes on your authors array š
. Blame it on it being Monday morning. It goes on your reference inside the array!Also, you had
fitlersand
$exsitingprojects, so once I changed them to
filterand
$existingProjects, plus corrected my misleading placement I got it to work!
export default { title: 'Recommendation', name: 'recommendation', type: 'document', fields: [ { title: 'Projects', name: 'projects', type: 'array', of: [ { title: 'Related Projects', type: 'reference', to: [{type: 'ref'}], options: { filter: ({document}) => { const existingProjects = document.projects.map(project => project._ref).filter(Boolean) return { filter: '!(_id in $existingProjects)', params: { existingProjects } } } } } ], } ] }
Sep 27, 2021, 6:49 PM
Ah, yes the validation option won't remove the option from the list, just throw an error when you do select it. That's why sometimes I prefer to just filter the list so that it's not even an option. And I was wrong when I said the filter goes on your authors array š
. Blame it on it being Monday morning. It goes on your reference inside the array!Also, you had
fitlersand
$exsitingprojects, so once I changed them to
filterand
$existingProjects, plus corrected my misleading placement I got it to work!
export default { title: 'Recommendation', name: 'recommendation', type: 'document', fields: [ { title: 'Projects', name: 'projects', type: 'array', of: [ { title: 'Related Projects', type: 'reference', to: [{type: 'ref'}], options: { filter: ({document}) => { const existingProjects = document.projects.map(project => project._ref).filter(Boolean) return { filter: '!(_id in $existingProjects)', params: { existingProjects } } } } } ], } ] }
Sep 27, 2021, 6:49 PM
With the initial value: if it's not parameterized, you'll need to tell it the
This will only work on new documents, though. If you'd like to add it to previously created docs, you would have to mutate them via the Mutations API.
_typeand
_ref:
{ name: 'authors', title: 'Authors', type: 'array', of: [ { type: 'author' } ], initialValue: [ { _type: 'author', _ref: '<id-of-author-doc>' } ] },
Sep 27, 2021, 6:59 PM
With the initial value: if it's not parameterized, you'll need to tell it the
This will only work on new documents, though. If you'd like to add it to previously created docs, you would have to mutate them via the Mutations API.
_typeand
_ref:
{ name: 'authors', title: 'Authors', type: 'array', of: [ { type: 'author' } ], initialValue: [ { _type: 'author', _ref: '<id-of-author-doc>' } ] },
Sep 27, 2021, 6:59 PM
C
user M
the array reference filter works as expected! š Do you have any recommendation for how I could move it into a separate utilsarea of sanity and re-use that across other of my references to keep my other references DRY with the same functionality? Or is this more appropriate to build a custom Sanity Reference component?
Also, big lol on
fitlersš¤¦āāļø I totally didn't catch it until re-reading it 3 times so no worries.
Regarding the initial value reference in an array, I see your code example includes author as if its an object. Here's what my code looks like today
{ name: 'authors', title: 'Authors', type: 'array', of: [ { type: 'reference', to: {type: 'person'} } ], initialValue: { _type: 'reference', to: { _type: 'person', _ref: '9122a1cc-40d0-4120-9f30-3e997007896c' } }, },
My ideal use case is that an editor already has a preassigned value in the array of that specific person reference, but can add additional and/or remove that one easily
Sep 27, 2021, 7:14 PM
I'll have to play with extracting the filter into a separate util, but that's a good idea. Especially as you start building custom Structures you'll find yourself repeating the same basic syntax in many places.
Sep 27, 2021, 7:20 PM
C
user M
so moving this initial value works in the sense that I still have to click the "add" button but then it autocompletes to my author everytime, which is not the behavior I'm looking for. Ideally, with the creation of each new post object, the author is already prefilled without clicking add, and then initialValue is left empty within the reference element so I don't get this behavior.This is the code producing this behavior:
{ name: 'authors', title: 'Authors', type: 'array', of: [ { Title: 'Author', type: 'reference', to: {type: 'person'}, initialValue: { _type: 'person', _ref: '9122a1cc-40d0-4120-9f30-3e997007896c' } } ] },
Sep 27, 2021, 7:22 PM
C
user M
so moving this initial value works in the sense that I still have to click the "add" button but then it autocompletes to my author everytime, which is not the behavior I'm looking for. Ideally, with the creation of each new post object, the author is already prefilled without clicking add, and then initialValue is left empty within the reference element so I don't get this behavior.This is the code producing this behavior:
{ name: 'authors', title: 'Authors', type: 'array', of: [ { Title: 'Author', type: 'reference', to: {type: 'person'}, initialValue: { _type: 'person', _ref: '9122a1cc-40d0-4120-9f30-3e997007896c' } } ] },
Sep 27, 2021, 7:22 PM
Ah, you're right, it would have to be something like this:
Then, when you create a new document it should automatically add it without having to click anything.
{ name: 'authors', title: 'Authors', type: 'array', of: [ { type: 'reference', to: [ { type: 'person' } ] } ], initialValue: [ { _ref: '<id-of-person-doc>' } ] },
Sep 27, 2021, 7:29 PM
C
Beautiful! Tested and working on Localhost! Big Thanks for all the help this Monday morning/afternoon (PST)
user M
!Sep 27, 2021, 7:37 PM
C
Beautiful! Tested and working on Localhost! Big Thanks for all the help this Monday morning/afternoon (PST)
user M
!Sep 27, 2021, 7:37 PM
Nothing quite like starting your week off with some fun challenges! Thanks for helping wake my brain up!
Sep 27, 2021, 7:38 PM
C
FYI, I DRY'ed that reference filter up a little with this. Just not sure how to replace the
document.[parentArray].mapin a meaningful way. I tried to create a const and pass the projects in the filter params but that resulted in
undefined.maperrors
options: { filter: ({document}) => { const existingReferences = document.projects.map(item => item._ref).filter(Boolean) return { filter: '!(_id in $existingReferences)', params: { existingReferences } } } }
Sep 27, 2021, 8:27 PM
C
FYI, I DRY'ed that reference filter up a little with this. Just not sure how to replace the
document.[parentArray].mapin a meaningful way. I tried to create a const and pass the projects in the filter params but that resulted in
undefined.maperrors
options: { filter: ({document}) => { const existingReferences = document.projects.map(item => item._ref).filter(Boolean) return { filter: '!(_id in $existingReferences)', params: { existingReferences } } } }
Sep 27, 2021, 8:27 PM
I got it working with:
Then in your doc:
// ./utils/getFilter.js export const getFilter = (document , field) => { const existingEntries = document[field].map(existingEntry => existingEntry._ref).filter(Boolean) return { filter: '!(_id in $existingEntries)', params: { existingEntries } } }
import { getFilter } from "../utils/getFilter" export default { title: 'Recommendation', name: 'recommendation', type: 'document', fields: [ { title: 'Projects', name: 'projects', type: 'array', of: [ { title: 'Related Projects', type: 'reference', to: [{type: 'ref'}], options: { filter: ({document}) => { return getFilter(document, 'projects') } } } ], } ] }
Sep 27, 2021, 9:00 PM
C
user M
You're a superstar!! š /utils/getFilter.jsin my parent
studiodirectory or within
schemas?
/studio/utils...
Sep 27, 2021, 9:35 PM
Aw, thanks! Hmm, I usually put the
utilsor
libfolders directly underneath the root Studio folder.
Sep 27, 2021, 9:38 PM
There's a really good guide on setting up your folder structure somewhere around here but I can't find it right now. I'll link it if I do!
Sep 27, 2021, 9:40 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.