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

Converting string tags to reference IDs in Sanity schema using migration script

27 replies
Last updated: Jun 2, 2022
When I first set up my schema, I added tags in the form of strings - just giving a quick string array I could reference down the line. I'm now rethinking that and want to set up a separate tags schema. Is there an easy way to quickly convert my existing strings into references, or am I looking at a manual job to do that? 😂
Jun 2, 2022, 10:36 AM
You could write a migration script. It‘s not overly trivial, but should be doable by fiddling a little bit with it.
Jun 2, 2022, 10:37 AM
Jun 2, 2022, 10:37 AM
You might want to back up your dataset before running your migration. 🙂
Jun 2, 2022, 10:38 AM
I'll give that a read through, thank you! 😄
Jun 2, 2022, 10:40 AM
user F
Where can I find additional data on the options available in the
patch
object (following the migrating-data link)? In some cases, my tags array has a couple of strings, so I'd need to be able to map through and create/link a reference, I suspect?
Jun 2, 2022, 11:10 AM
Right, that’s correct.
Jun 2, 2022, 11:15 AM
So I would do it like this: first query tag documents so you can map a string to a reference ID. Then do the migration. For each tag as a string, look up the reference ID in the map, and create an object like this:
{ _type: 'reference', _ref: 'id-of-the-document', _key: nanoid() }
Jun 2, 2022, 11:18 AM
okay, would it be sensible to make each of my categories manually in advance of trying to migrate in that case? At the minute, my "categories" is just an empty, freshly made schema.
Jun 2, 2022, 11:22 AM
Ah yes, absolutely.
Jun 2, 2022, 11:24 AM
I would definitely recommend that to make the migration simpler. 🙂
Jun 2, 2022, 11:24 AM
so just to get a clearer idea in my head here then:• find all documents to update
• find all categories and their IDs
• loop through each document and
set
the category using the matching tag string (can I do multiple of these in one patch, or would I need a patch per change?)
Jun 2, 2022, 11:26 AM
Right now, your category field is an array of strings or a string?
Jun 2, 2022, 11:27 AM
the existing one uses the following schema:
{
  title: "Tags",
  name: "tags",
  type: "tags",
  options: {
    closeMenuOnSelect: true,
    frozen: false,
  },
},

Jun 2, 2022, 11:30 AM
I'd be changing it to the following:
{
  title: "Categories",
  name: "Categories",
  type: "array",
  of: [
    {
      type: "reference",
      to: [{ type: "category" }],
    },
  ],
},
Jun 2, 2022, 11:31 AM
Ah yes, you’re using this plugin: https://github.com/pcbowers/sanity-plugin-tags
Jun 2, 2022, 11:32 AM
Jun 2, 2022, 11:33 AM
Essentially the same thing from a schema standpoint.
Jun 2, 2022, 11:34 AM
Right, so you create all your categories. Then in your migration script, you start by querying your categories to create a hash mapping their string to their Sanity ID. Then during your migration, for each document you patch, you map its array of categories to transform it into an array of reference objects.
Jun 2, 2022, 11:35 AM
and that map can be done within a single patch instance per document?
Jun 2, 2022, 11:36 AM
const buildPatches = docs =>
  docs.map(doc => ({
    id: doc._id,
    patch: {
      set: {
        Categories: doc.Categories.map(category => ({
          _type: 'reference',
          _ref: CATEGORIES_MAP[category],
          _key: nanoid()
        }))
      },
      ifRevisionID: doc._rev,
    },
  }))
Jun 2, 2022, 11:37 AM
I’d say something like this.
Jun 2, 2022, 11:37 AM
okay, let me get some categories set up, and I'll give that a try. Thank you!
Jun 2, 2022, 11:38 AM
Really, back up your dataset before.
Jun 2, 2022, 11:39 AM
is that
sanity dataset export
?
Jun 2, 2022, 11:40 AM
I believe so.
Jun 2, 2022, 11:46 AM
That worked perfectly, thanks for all your help!
Jun 2, 2022, 12:27 PM
Yay! Amazing. 😄
Jun 2, 2022, 12:32 PM

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?