Migration from boolean to string value using mutations in Sanity

Sanity has a great way to migrate data. I found myself converting a boolean property to a string in a sanity document. My boolean property acts as a feature toggle that I now want to extend to beta users. I'll do my examples as an airplane company ✈️ This is how I chose to tackle the issue. My boolean property looks like this:

{
  title: "Has in-plane entertainment",
  name: "hasInPlaneEntertainment",
  type: "boolean"
}

For the migration/mutation to work we need to keep this value for now. I want to introduce a string that has 3 alternatives: disabled, enabled for beta users, and enabled for all users. We call this new field inPlaneEntertainmentState.

{
  title: "In-plane entertainment",
  name: "inPlaneEntertainmentState",
  type: "string",
  options: {
    list: [
      { title: "Disabled", value: "Disabled" },
      { title: "Enabled for beta users", value: "LimitedToBetaUsers" },
      { title: "Enabled for all users", value: "Enabled" }
    ]
  }
}

Now I want to set the state to Disabled if the property is set to false and set the state to Enabled if the property is set to true. Here we can leverage the power of sanity.io mutations and clever use of queries. Here's my mutation:

{
  "mutations": [
    {
      "patch": {
        "query": "*[_type == 'airplane' && hasInPlaneEntertainment]",
        "set": {
          "inPlaneEntertainmentState": "Enabled"
        }
      }
    },
    {
      "patch": {
        "query": "*[_type == 'airplane' && !hasInPlaneEntertainment]",
        "set": {
          "inPlaneEntertainmentState": "Disabled"
        }
      }
    }
  ]
}

We make two mutations here. One for the true value and one for the false value. Make sure to dry run this first:

curl 'https://<projectid>.api.sanity.io/v2021-06-07/data/mutate/<dataset>?dryRun=true' \
    -H 'Authorization: Bearer <token>' \
    -H 'Content-Type: application/json' \
    --data-binary '{"mutations":[{"patch":{"query":"*[_type == \'airplane\' && hasInPlaneEntertainment]","set":{"inPlaneEntertainmentState":"Enabled"}}},{"patch":{"query":"*[_type == \'airplane\' && !hasInPlaneEntertainment]","set":{"inPlaneEntertainmentState":"Disabled"}}}]}'

After everything is successful you can the run mutation without the dry run flag. That's it! We've now migrated to a new field and we can delete the old boolean value.