Updating default field value in Sanity.io using a script

10 replies
Last updated: Nov 2, 2021
Hi all, 👋
I got a question related to data migration or "massive" data updates. I have updated my
post document and added a boolean field called
isHighlighted
. I'd like that field to be
false
by default. Putting the property
initialValue: false
on that document property does work for new posts.
But my question is, how do I create a script that sets this property to false in all my already created
posts? Thx in advance 🤗
AI Update

Great question! You'll want to use a migration script to update all existing posts with the new isHighlighted field. Sanity provides a CLI migration tool that's perfect for this scenario.

Using the Sanity CLI Migration Tool

First, create a new migration script:

npx sanity@latest migration create

This will generate a migration file where you can write your logic. Here's what your migration should look like:

import {defineMigration, at, setIfMissing} from 'sanity/migrate'

export default defineMigration({
  title: 'Set isHighlighted to false for all posts',
  documentTypes: ['post'],
  
  migrate: {
    document(doc, context) {
      return at('isHighlighted', setIfMissing(false))
    }
  }
})

The key here is using setIfMissing, which only sets the value if the field doesn't already exist. This means:

  • Existing posts without the field will get isHighlighted: false
  • Any posts that already have a value won't be changed
  • The migration is idempotent (safe to run multiple times)

Running the Migration

The CLI runs in dry-run mode by default, so you can safely test it first:

npx sanity@latest migration run

Once you've verified the changes look correct, run it for real:

npx sanity@latest migration run --no-dry-run

Alternative: Using sanity exec

If you prefer a more direct approach, you can also use sanity exec with a custom script:

// scripts/setIsHighlighted.js
import {getCliClient} from 'sanity/cli'

const client = getCliClient()

const fetchDocuments = () => 
  client.fetch(`*[_type == "post" && !defined(isHighlighted)]`)

const buildPatches = docs =>
  docs.map(doc => ({
    id: doc._id,
    patch: {
      setIfMissing: {isHighlighted: false}
    }
  }))

const createTransaction = patches =>
  patches.reduce((tx, patch) => tx.patch(patch.id, patch.patch), client.transaction())

const commitTransaction = tx => tx.commit()

const migrateNextBatch = async () => {
  const documents = await fetchDocuments()
  if (documents.length === 0) {
    console.log('No more documents to migrate!')
    return
  }
  console.log(`Migrating batch of ${documents.length} documents...`)
  const patches = buildPatches(documents)
  const transaction = createTransaction(patches)
  await commitTransaction(transaction)
  await migrateNextBatch()
}

migrateNextBatch().catch(err => {
  console.error(err)
  process.exit(1)
})

Run it with:

npx sanity exec scripts/setIsHighlighted.js --with-user-token

The CLI migration tool is generally recommended as it provides better visual feedback and automatic batching to avoid rate limits. Both approaches will work, but the migration tool is more user-friendly for this type of schema update! 🎉

Hey Tomas! You'll have to create a patch for this. Do you prefer to use the JS client or the CLI for this?
Hi
user M
, thx for replying. Well, it's only 28 articles
do you have any suggestion?
and also, I going over this documentation in sanity's site:
https://www.sanity.io/docs/migrating-data
I usually write a JS script because it's what I'm more comfortable with. You need to do a few things: configure your client => fetch all of the documents that need to be changed => loop through the documents and commit the changes to each one. The following you could do something like the following:
import sanityClient from 'part:@sanity/base/client'
const client = sanityClient.withConfig({apiVersion: '2021-03-25'})

const query = `*[_type == 'post' && !defined(isHighlighted)]` //get all of your posts that do not have isHighlighted set

const mutateDocs  = async (query) => {
  const docsToMutate = await client.fetch(query, {})
  for (const doc of docsToMutate) {
      const mutation = {
        isHighlighted: true
      }
        console.log('uploading')
        client
        .patch(doc._id) // Document ID to patch
        .set(mutation) // Shallow merge
        .commit() // Perform the patch and return a promise
        .then((updatedDoc) => {
          console.log('Hurray, the doc is updated! New document:')
          console.log(updatedDoc._id)
        })
        .catch((err) => {
          console.error('Oh no, the update failed: ', err.message)
        })
    }
}

mutateDocs(query) 
You could then run the script using
sanity exec --with-user-token
.
I usually write a JS script because it's what I'm more comfortable with. You need to do a few things: configure your client => fetch all of the documents that need to be changed => loop through the documents and commit the changes to each one. The following you could do something like the following:
import sanityClient from 'part:@sanity/base/client'
const client = sanityClient.withConfig({apiVersion: '2021-03-25'})

const query = `*[_type == 'post' && !defined(isHighlighted)]` //get all of your posts that do not have isHighlighted set

const mutateDocs  = async (query) => {
  const docsToMutate = await client.fetch(query, {})
  for (const doc of docsToMutate) {
      const mutation = {
        isHighlighted: true
      }
        console.log('uploading')
        client
        .patch(doc._id) // Document ID to patch
        .set(mutation) // Shallow merge
        .commit() // Perform the patch and return a promise
        .then((updatedDoc) => {
          console.log('Hurray, the doc is updated! New document:')
          console.log(updatedDoc._id)
        })
        .catch((err) => {
          console.error('Oh no, the update failed: ', err.message)
        })
    }
}

mutateDocs(query) 
You could then run the script using
sanity exec --with-user-token
.
you know I had forgotten about the groq method
defined(_field_)
available in the queryu
your script rocked as well
thank you for that
Very happy to help!

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?