How AI is powering better personalization in e-commerce [with Vercel]. Sign up now

Normalize Portable Text blocks

Migration script to normalize Portable Text blocks across your whole dataset

By Per-Kristian Nordnes


normalizeAllBlocks.js

import sanityClient from "part:@sanity/base&client";
import { normalizeBlock } from "@sanity/block-tools";
import { extractWithPath } from"@sanity/mutator";

// Act on all documents
const query = "*[]";

// Adjust the decorators to the set you want to allow
const allowedDecorators = [
  "strong",
  "em",
  "code",
  "underline",
  "strike-through",
  "sub",
  "sup"
];


function convertPath(pathArr) {
  return pathArr
    .map(part => {
      if (Number.isInteger(part)) {
        return `[${part}]`;
      }
      return `.${part}`;
    })
    .join("")
    .substring(1);
}

client.fetch(query).then(results => {
  const patchedDocuments = [];
  results.forEach(async result => {
    const matches = extractWithPath('..[_type=="block"]', result);
    let patch = client.patch(result._id);
    matches.forEach(match => {
      const block = match.value;
      const path = convertPath(match.path);
      const normalizedBlock = normalizeBlock(block, { allowedDecorators });
      const patchData = { [path]: normalizedBlock };
      patch = patch.set(patchData);
    });
    const patchLength = patch.operations.set
      ? Object.keys(patch.operations.set).length
      : 0;
    if (patchLength > 0) {
      patchedDocuments.push(result._id);
      await patch.commit();
      console.log(
        `Patched ${patchLength} blocks in document ${result._id}`
      );
    }
  });
  console.log(
    `Patched ${patchedDocuments.length} documents with ids: ${JSON.stringify(
      patchedDocuments,
      null,
      2
    )}`
  );
});

NOTE: We have shipped content migration tooling for Sanity (v3.27.0) that makes the approach described here. Check out the documentation and cheat sheet for learning how to do this with the proper tooling.

This migration script will go through all your documents, look for all Portable Text blocks and filter out decorators that aren't present in the allowedDecorators array. It will build a transaction of patches to update these blocks.

You can run this script with sanity exec normalizeAllBlocks.js --with-user-token. It might be wise to export your dataset first since this script changes data.

Contributor

Per-Kristian Nordnes

Fullstack developer at Sanity.io

Norway

Visit Per-Kristian Nordnes's profile