Discussion on validating uniqueness of hospital names in a document, with code snippets provided.

16 replies
Last updated: Jul 27, 2021
can anyone guide me on how to validate uniqueness in a document i have tried but not working I want to validate hospital namesvalidation: Rule => Rule.required().custom((input)=>{       
          return client.fetch(
count(*[_type == "hospitalManagement" && title == "${input}"])
)          .then(count  =>  {
            if (count > 0){
              return 'Title needs to be unique'
            }else{
              return true
            }
          })
        })
AI Update

I can see the issue with your validation code. There are a few problems that need to be fixed for the uniqueness validation to work properly.

The main issues are:

  1. String interpolation syntax: You're using "${input}" instead of proper template literal syntax with backticks
  2. The query will always find at least 1 document: When editing an existing document, it will find itself, so the count will never be 0
  3. You need to exclude the current document from the count

Here's the corrected version:

validation: Rule => Rule.required().custom(async (input, context) => {
  const client = context.getClient({apiVersion: '2021-03-25'})
  
  // Get the current document ID to exclude it from the search
  const currentDocId = context.document._id
  
  const query = `count(*[_type == "hospitalManagement" && title == $title && _id != $currentId])`
  const params = {
    title: input,
    currentId: currentDocId.replace('drafts.', '') // Remove 'drafts.' prefix if present
  }
  
  const count = await client.fetch(query, params)
  
  if (count > 0) {
    return 'Hospital name must be unique'
  }
  return true
})

Key changes:

  1. Use backticks for the GROQ query string (template literals)
  2. Use parameterized queries ($title and $currentId) instead of string interpolation - this is safer and handles special characters properly
  3. Exclude the current document with _id != $currentId so you don't count the document being edited
  4. Handle draft IDs by removing the drafts. prefix when comparing IDs
  5. Make the function async and use await for cleaner code

The validation will now properly check if another document (excluding the current one) already has the same hospital name.

You can read more about custom validation and asynchronous validation using the client in the Sanity documentation.

Do you want hospital names to be unique across all documents or just those titles of the type
hospitalManagement
?
Across all Document
Across all Document
I got stuck at some cases its working and in some cases its not can you please guide me through this.
user A
I don’t know that this is the best way to approach your use case, as something like RxJS might be more appropriate, but it seems to at least satisfy the validation when I tested it a bit. Perhaps it can at least be a starting point.

import sanityClient from 'part:@sanity/base/client'

const client = sanityClient.withConfig({ apiVersion: '2021-07-22'})

export function isUniqueAcrossAllDocuments(title, options) {
  const {document} = options

  const id = document._id.replace(/^drafts\./, '')
  const params = {
    draft: `drafts.${id}`,
    published: id,
    title
  }

  const query = `!defined(*[!(_id in [$draft, $published]) && title == $title][0]._id)`

  return client.fetch(query, params)
}

export default {
  name: 'vivek',
  title: 'Vivek Unique Documents',
  type: 'document',
  fields: [
    {
      name: 'title',
      title: 'Title',
      type: 'string',
      validation: Rule => Rule.required().custom(async (doc, context) => {
        const result = await isUniqueAcrossAllDocuments(doc, context)
        return result ? true : 'Titles must be unique.'
      })
    }
  ]
}
Here’s what’s happening from top-to-bottom:
• We’re importing and configuring the Sanity client, which we’ll use to fetch all documents.
• We’re setting up a function that will take in two parameters: the title of the current document and an object that will give us access to the document’s
_id
.• We use some logic to check (1) if the current
_id
is defined as a draft or published document anywhere other than itself and where (2) the title is the same as the title of the current document; we then use the
!defined()
GROQ function to return true if it’s not defined (in other words, return true when the document
title
is unique).• If the title is not unique, we return a string, which the studio’s validation prints out as an error (given we used the
required()
method at the start) and prevents the user from publishing.As with all validation in the studio, this is all studio-only so there’s nothing preventing a non-unique title from being added via the API.
Thanks for the help
user A
will go through this approach.
No problem! Please let me know how it goes.
Yeah sure👍
user A
it worked Big thank you to you. I also want to appreciate your content and videos in youtube are awesome keep up the good work👍.
user A
it worked Big thank you to you. I also want to appreciate your content and videos in youtube are awesome keep up the good work👍.
Glad to hear it, Vivek!
Hello
user A
if i want to do validation of blank spaces at start and also of special character then?export function isUniqueAcrossAllDocuments(title, options) {
      const {document} = options
      const id = document._id.replace(/^drafts\./, '')
      const params = {
        draft: 
drafts.${id}
,        published: id,
        title
      }
      const query = 
!defined(*[!(_id in [$draft, $published]) && title == $title][0]._id)
      
      return client.fetch(query, params)
    }
    export function isValid(title){
      if(title===undefined){
        return true;
      }
      const regex = /^[a-zA-Z1-9\s]+$/;
      if (!regex.test(title)) {
        return "Invalid character"
      } 
      if(title.startsWith(" ")){
        console.log("contains space");
        return "Can't Input Blank Space at Start"
      }
    }
export default {
    name: 'hospitalManagement',
    title: 'Hospital Management',
    type: 'document',
    
    //__experimental_actions: ['create','update', 'delete','publish'],
    
    
    fields: [
      {
        name: 'title',
        title: 'Name Of Hospital',
        type: 'string',
        
        validation: Rule => Rule.required().custom(async (doc, context) => {
          console.log(context)
          var res = context.document.title;
          console.log(res);
          const result = await isUniqueAcrossAllDocuments(doc, context)
          isValid(res)
          
          return result ? true : 'Titles must be unique.'
        })
      },
how to integrate my function isvalid in this
i have created the logic for it just stuck on integrating it
Resolved the issue.

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?