How to Do Bulk Updates with References in Sanity
I had a hard time figuring out how to handle bulk updates (patches) for articles in Sanity. While there is documentation about modifying general arrays and text fields, there was nothing about modifying related fields in bulk.
Through a bit of trial and error I figured out that it was relatively similar to a create
call.
The safest way to make a bulk update is using transactions. Set up your async function with by calling sanityClient.transaction()
. You can then chain all your patch
modifications together thanks to the Sanity client.
transaction.patch(article._id, (p) => { return p.insert("after", "tags[-1]", [ITEM_REF]);});
In the snippet above I am adding a predefined relational reference at the end of the array field.
Commonly you won’t need to modify all of your articles. Below is a simple example of how you can tag articles containing a keyword by running a patch transaction using the Sanity client.
import { createClient } from "@sanity/client";
const sanityClient = createClient({ projectId: "<YOUR_PROJECT_ID>", dataset: "production", # this may change depending on what you named it useCdn: false, apiVersion: "2023-09-28", token: "<YOUR TOKEN HERE>",});
export default sanityClient;
Now import the Sanity client.
import sanityClient from "./sanityClient";
const ITEM_REF = { _type: "reference", _ref: "<YOUR_REF_ID>", # replace with your ID string from Sanity.};
interface Article { content: any[]; _id: string; tags: string[];}
const updateArticles = async (articlesToUpdate: Article[]) => { const transaction = sanityClient.transaction();
articlesToUpdate.forEach((article: any) => { transaction.patch(article._id, (p) => { return p.insert("after", "tags[-1]", [ITEM_REF]); }); });
try { const result = await transaction.commit({ autoGenerateArrayKeys: true, }); console.log("Transaction committed:", result); } catch (error) { console.error("Transaction failed:", error); }};
const runUpdate = async () => { try { // Get all articles from sanity const articles: Article[] = await sanityClient.fetch( `*[_type == "article" && title match ['My Keyword**']] { _id, title, tags[]->{ _id, name, "slug": slug.current }, } | order(updatedDate desc, publishedAt desc)` );
let articlesToUpdate: Array<Article> = [];
articles.forEach((article: any) => { if ( article && article.tags && article.tags.length && article.tags.every((tag: any) => tag.slug !== "target-slug") ) { articlesToUpdate.push(article); } });
await updateArticles(articlesToUpdate); } catch (error) { console.error(error); }};
runUpdate();
Running the Update with TS Node Dev
To run this, you could set up a simple typescript project. Run ts-init and install the necessary dependencies, namely the Sanity client.
{ "name": "sanity-update", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "@types/node": "^20.9.0", "typescript": "^5.2.2" }, "dependencies": { "@sanity/client": "latest", }}
Run npx ts-node transform.ts
and your articles will be updated using a Sanity client patch transaction.