Knut Melvær
Knut is a principal developer marketing manager at Sanity.io
This migration scripts lets you migrate documents to a new type.
import {createClient} from '@sanity/client'
type Doc = {
_id: string
_rev?: string
_type: string
incomingReferences?: Doc[]
}
const token = process.env.SANITY_TOKEN
const projectId = process.env.SANITY_PROJECT_ID
const dataset = process.env.SANITY_DATASET
const apiVersion = '2023-03-01'
const client = createClient({
apiVersion,
projectId,
dataset,
token,
})
const OLD_TYPE = 'movie'
const NEW_TYPE = 'film'
const fetchDocuments = () =>
client.fetch(
`*[_type == $oldType][0...10] {..., "incomingReferences": *[references(^._id)]{...}}`,
{oldType: OLD_TYPE}
)
const buildMutations = (docs: Doc[]) => {
const mutations: any = []
docs.forEach((doc) => {
console.log('movie', doc._id)
// Updating an document _type field isn't allowed, we have to create a new and delete the old
const newDocId = `${doc._id}-migrated`
const newDocument = {...doc, ...{_id: newDocId, _type: NEW_TYPE}}
delete newDocument.incomingReferences
delete newDocument._rev
mutations.push({create: newDocument})
if (!doc.incomingReferences) {
return
}
// Patch each of the incoming references
doc.incomingReferences.forEach((referencingDocument) => {
console.log('ref', referencingDocument._id)
// ⚠️ We're assuming the field is named the same as the type!
// There might be another structure involved, perhaps an array, that needs patching
const updatedReference = {
[NEW_TYPE]: {
_ref: newDocId,
_type: 'reference',
},
}
mutations.push({
id: referencingDocument._id,
patch: {
set: updatedReference,
unset: [OLD_TYPE],
ifRevisionID: referencingDocument._rev,
},
})
})
// Apply the delete mutation after references have been changed
mutations.push({delete: doc._id})
})
return mutations.filter(Boolean)
}
const createTransaction = (mutations: any) => {
return mutations.reduce((tx: any, mutation: any) => {
if (mutation.patch) {
return tx.patch(mutation.id, mutation.patch)
}
if (mutation.delete) {
return tx.delete(mutation.delete)
}
if (mutation.create) {
return tx.createIfNotExists(mutation.create)
}
}, client.transaction())
}
const migrateNextBatch: any = async () => {
const documents = await fetchDocuments()
if (documents.length === 0) {
console.log('No more documents to migrate!')
return null
}
const mutations = buildMutations(documents)
const transaction = createTransaction(mutations)
await transaction.commit()
return migrateNextBatch()
}
migrateNextBatch().catch((err: any) => {
console.error(JSON.stringify(err, null, 2))
process.exit(1)
})
This example shows how you can perform a migration where a document _type field is changing. It will migrate documents in batches of 10 and continue patching until no more documents are returned from the query.
A few things to note:
_type
field on a document isn't allowed. The solution to this is to create a duplicate with a new _id
and _type
, then delete the old document and patch all referencing documents with the new _id
Run this script with the command npx sanity exec --with-user-token migrateDocumentType.ts
in a studio folder. This script deletes and changes data, so it might be wise to export your dataset first.
Knut is a principal developer marketing manager at Sanity.io
This can be used for blogs or articles where you want to possibly display next and previous article buttons
Go to Get current post, previous post, and next postHow to automatically generate linked headings with a custom serializer
Go to Anchored Headings for Portable TextMigration script to convert plain text to block content across your content lake
Go to Migrate plain text field to Portable TextSimple content type for a question and answer pattern
Go to Frequently asked questions