Prevent duplicate references in Sanity array field

7 replies
Last updated: Jan 24, 2022
Hey!
Is it possible to prevent duplicates of a reference type from being entered into an array? I'm making a quiz and in the quiz there is a question where a user is allowed to choose images. Each image needs to be tagged with a collection. I'm able to get this to work, but I would like to prevent the tag("collection") from being added to an image more than once. I'll post my code in a comment below.
AI Update

Yes, you can prevent duplicate references in an array using custom validation! Sanity's validation system supports this through the custom() method that can check for unique values.

Here's how to prevent duplicate collection tags from being added to your image array:

defineField({
  name: 'imageTags',
  type: 'array',
  of: [
    {
      type: 'object',
      fields: [
        {
          name: 'image',
          type: 'reference',
          to: [{type: 'image'}]
        },
        {
          name: 'collection',
          type: 'reference',
          to: [{type: 'collection'}]
        }
      ]
    }
  ],
  validation: (rule) => rule.custom((items) => {
    if (!items) return true;
    
    // Extract all collection reference IDs
    const collectionIds = items
      .map(item => item.collection?._ref)
      .filter(Boolean);
    
    // Check for duplicates
    const duplicates = collectionIds.filter(
      (id, index) => collectionIds.indexOf(id) !== index
    );
    
    if (duplicates.length > 0) {
      return 'Each collection can only be used once';
    }
    
    return true;
  })
})

This validation works by:

  1. Extracting all the collection reference IDs from your array items
  2. Checking if any ID appears more than once
  3. Returning an error message if duplicates are found, or true if all are unique

The validation runs in real-time as editors add items, and will prevent publishing if duplicates exist. You can also use a more nuanced approach with different severity levels:

validation: (rule) => rule.custom((items) => {
  // ... same duplicate check logic ...
  if (duplicates.length > 0) {
    return {
      message: 'Each collection should only be used once',
      level: 'warning' // or 'error' or 'info'
    };
  }
  return true;
})

Using 'warning' instead of 'error' would allow publishing but still alert the user, while 'info' would just provide helpful guidance.

Keep in mind that validation only runs in the Studio interface - if you're creating content via API, you'll need separate server-side validation as mentioned in the field validation documentation.

Show original thread
7 replies
export default {
  name: "imageOptions",
  title: "Image Options",
  type: "object",
  fields: [
    {
      name: "images",
      title: "Images",
      type: "array",
      of: [
        {
          name: "image",
          title: "Image",
          type: "image",

          fields: [
            {
              name: "alt",
              title: "Alternative text",
              type: "localeString",
            },

            {
              name: "tags",
              title: "tags",
              type: "array",
              of: [
                {
                  type: "reference",
                  to: [{ type: "collections" }],
                },
              ],
            },
          ],
        },
      ],
    },
  ],
};

Hey User. This should be possible by adding a
unique()
validation rule (https://www.sanity.io/docs/array-type#unique()-49ee9907c730 ) to the
tags
array.
You'd add it like this:


{
  name: "tags",
  title: "tags",
  type: "array",
  validation: Rule => Rule.unique(),
  of: [
    {
      type: "reference",
      to: [{ type: "collections" }],
    },
  ],
},
And then you should see that Studio starts validating it accordingly:
WOW!! That is exactly what I needed. Thank you so much for the quick reply.
Can I ask a quick follow up? is it possible to setup the reference as a tags layout? I haven't been able to get it to work.
something like...


 {
              name: "tags",
              title: "tags",
              type: "array",
              options: {
                layout: 'tags'
              },
              validation: Rule => Rule.unique(),
              of: [
                {
                  type: "reference",
                  to: [{ type: "collections" }],
                },
              ],
            }

Unfortunately the tag layout only works for an array of strings at the moment, not references πŸ˜•.
NP, Thanks for the help!
No problem. Let us know if you have any other questions!

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.

Was this answer helpful?