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

Filtering articles by category in Sanity.io

12 replies
Last updated: Dec 22, 2022
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:

options: {
             layout: 'tags',
             filter: '!(_id in path("drafts.**")) && $categoryId in categories[]._ref)',
             params: {categoryId: document._id}
         },
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?
Dec 20, 2022, 2:33 PM
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
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
What does the
categoryName
schema look like on that document?
Dec 20, 2022, 9:14 PM
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
_id
in the arrays of
_refs
works 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
That makes sense to me, but I can't seem to make it work.
Minimal example of my filtering:

filter: ({ document }) => {
                        return {
                          filter: '$categoryId in categories[]._ref',
                          params: {
                            categoryId: document._id
                          },
                        };
                      }, 
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.
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
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
Thanks. I'll work on this today.
Dec 21, 2022, 6:23 PM
Thank you! 🙏
Dec 21, 2022, 6:24 PM
Ok, this should work for you:
{
      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,
                },
              }
            },
          },
        },
      ],
    },
Previously, if the category document was a draft, the
_id
wouldn't match the
_ref
in the article document. In this method we control for that.
Dec 21, 2022, 6:47 PM
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.

Was this answer helpful?