Filtering articles by category in Sanity.io
12 replies
Last updated: Dec 22, 2022
M
Hello! Can anyone see what's wrong with my filter?
What I'm trying to accomplish: Have an array of references to Articles in my Category-document. The Articles should only be of the current category. An Article has an array of references to Categories. My idea was to check in the filter if the id of the current Category is present in the list of Categories in the Articles. But I get the attached error when I write this:
The first filter that chooses only published Articles works fine on its own. I've tried a few different but gotten the same error. Anyone know what I've done wrong?
What I'm trying to accomplish: Have an array of references to Articles in my Category-document. The Articles should only be of the current category. An Article has an array of references to Categories. My idea was to check in the filter if the id of the current Category is present in the list of Categories in the Articles. But I get the attached error when I write this:
options: { layout: 'tags', filter: '!(_id in path("drafts.**")) && $categoryId in categories[]._ref)', params: {categoryId: document._id} },
Dec 20, 2022, 2:33 PM
M
Progress: I've figured out that the mistake lies in how I'm finding the ID of the current document. Cause when I set a hardcoded ID for a category it works fine
Dec 20, 2022, 2:49 PM
M
So, I managed to do what I want to by comparing name field instead of id. If someone knows what I need to do to use the id of the current document I would much prefer to compare ids. This is what is currently working:
options: { layout: 'tags', filter: ({document}) => { return { filter: '$categoryName in categories[]->categoryName', params: {categoryName: document.categoryName} } } },
Dec 20, 2022, 3:33 PM
M
categoryName is just a string field in the category document
Dec 21, 2022, 7:47 AM
Ah, got it. The method of checking for the
_idin the arrays of
_refsworks if that field is a reference to another document. But you nailed it for the method of checking for a string in another document!
Dec 21, 2022, 4:47 PM
M
That makes sense to me, but I can't seem to make it work.
Minimal example of my filtering:
I don't get any error message. It just simply cannot find anything. I think I'm not going about finding the current document id correctly. If I switch out $categoryId in the filter with the actual id of a category it works, but I need the id to be the one belonging to the current document.
Minimal example of my filtering:
filter: ({ document }) => { return { filter: '$categoryId in categories[]._ref', params: { categoryId: document._id }, }; },
Dec 21, 2022, 5:05 PM
Can you share the schema for the two documents? I'll put together the filter for you.
Dec 21, 2022, 5:55 PM
M
A minimal version of them that includes how they reference each other:
// Category.jsx import {TagIcon} from '@sanity/icons' export default { name: 'category', type: 'document', title: 'Kategori', icon: () => <TagIcon />, fields: [ { name: 'categoryName', type: 'string', title: 'Navn', description: 'Dette navnet vil være på alle tagger for denne kategorien.' }, { name: 'featuredArticles', type: 'array', title: 'Utvalgte Artikler', of: [{ type: 'reference', to: [ {type: 'article'} ], options: { layout: 'tags', filter: ({ parent, document }) => { const existingEntries = parent .map((existingEntry) => existingEntry._ref); return { filter: '(!(_id in $existingEntries) && !(_id in path("drafts.**")) && $categoryId in categories[]._ref)', params: { existingEntries, categoryId: document._id }, }; }, }, }], }, ], preview: { select: { title: 'categoryName', }, prepare({title}) { return { title, media: <TagIcon /> } }, } }
// Article.js export default { name: 'article', type: 'document', title: 'Artikkel', fields: [ { name: 'articleTitle', type: 'string', title: 'Tittel', validation: Rule => Rule.required().min(10).max(200) }, { name: 'categories', type: 'array', title: 'Kategorier', of: [{ type: 'reference', to: [ {type: 'category'} ] }], options: { layout: 'tags' }, validation: Rule => Rule.required().min(1) } ], preview: { select: { title: 'articleTitle', subtitle: 'author', media: 'headerImage.uploadImage' } } }
Dec 21, 2022, 6:01 PM
M
Thank you! 🙏
Dec 21, 2022, 6:24 PM
Ok, this should work for you:
Previously, if the category document was a draft, the
{ name: 'featuredArticles', type: 'array', title: 'Utvalgte Artikler', of: [ { type: 'reference', to: [{type: 'article'}], options: { layout: 'tags', filter: ({parent, document}) => { const existingEntries = parent.map((existingEntry) => existingEntry._ref) const id = document._id.includes('drafts.') ? document._id.slice(7) : document._id return { filter: '!(_id in path("drafts.**")) && !(_id in $existingEntries) && references($categoryId)', params: { existingEntries, categoryId: id, }, } }, }, }, ], },
_idwouldn't match the
_refin the article document. In this method we control for that.
Dec 21, 2022, 6:47 PM
M
Awesome! It works perfectly!
Dec 22, 2022, 9:09 AM
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.