Happening this week! Hear how Amplitude built a self-serve marketing engine to drive growth 🚀

Patches

The valid patch types when using the direct HTTP mutations api.

It is good practice to use patches when modifying Sanity documents through the API. Ideally, you make the smallest, most specific patch possible for your changes so that if multiple scripts or users are modifying the same documents at the same time, Sanity is able to merge those changes in a sensible way.

A patch is a special mutation submitted through the mutations API endpoint. Since this endpoint is transactional you may submit one or several patches at once, potentially changing any number of documents in one single transaction. Here is an example of a full transaction submitting two patches at once (This sets the name property of the document with id "person-123" to "Remington Steele" and adds a reference to it to the end of the people-array of the document with the id "remingtons":

{
  "mutations": [
    {
      "patch": {
        "id": "person-1234",
        "set": {
          "name": "Remington Steele"
        }
      }
    },
    {
      "patch": {
        "id": "remingtons",
        "insert": {
          "after": "people[-1]",
          "items": [
            {
              "_type": "reference",
              "_ref": "person-1234"
            }
          ]
        }
      }
    }
  ]
}

Note: Generally the keys of the patches use JSONMatch syntax to target values for change. This syntax generally allows for paths like some.array[8].attribute, but can also do pattern matching, recursive search, and target multiple values at once. The full syntax is documented here.

Protip

JSONMatch is a variant of JSONPath that simplifies the syntax and eliminating to the maximum extent the number of special characters required to express a path.

set

set performs a shallow merge of its argument into the document. Each key in the argument is either an attribute or a JSON path.

Usage

{ "set": { attributeOrJSONPathExpression: any } }

Examples

Object properties

Set the field name to the value Bob and the nested field personalMetrics.height to 201:

{ "set": { "name": "Bob", "personalMetrics.height": 201 } }

Arrays

Set the text property to the value Do the thing! in all objects in the body array where the _type is cta:

{ "set": { "body[_type==\"cta\"].text": "Do the thing!" } }

Gotcha

Notice that the array filter ([_type == \"cta\"]) must use double quotes. If you are in JSON, you must escape them (\").

setIfMissing

setIfMissing is like set, except existing keys will be preserved and not overwritten.

unset

Deletes one or more attributes. Each entry in the argument is either an attribute or a JSON path. Missing attributes are ignored. Unset can also be used to delete elements of an array.

Usage

{ "unset": [ attributeOrJSONPathExpression, ... ] }

Example

{ "unset": ["foo", "bar"] }

insert

insert provides methods for modifying arrays, by inserting, appending and replacing elements via a JSONPath expression.

Appending

Inserts the string "a" at the end of the array some.array:

{
  "insert": {
    "after": "some.array[-1]",
    "items": ["a"]
  }
}

Insertion

Inserts the string "a" at index 2 before whatever was there:

{
  "insert": {
    "before": "some.array[2]",
    "items": ["a"]
  }
}

Prepend

This inserts the string "a" at the beginning of the array.

{
  "insert": {
    "before": "some.array[0]",
    "items": ["a"]
  }
}

Replace

This removes index 2 through the end of the array, replacing the content with "a".

{
  "insert": {
    "replace": "some.array[2:]",
    "items": ["a"]
  }
}

Advanced use of JSONMatch

NOTE: see the article on JSONMatch for more details

Finds the element that has key == 'abc-123' and inserts "a" after it.

{
  "insert": {
    "after": "some.array[key == \"abc-123\"]",
    "items": ["a"]
  }
}

Finds any object that has key == 'list-123' adds "a" at the beginning of its items array:

{
  "insert": {
    "before": "blocktext..[key=\"list-123\"].items[0]",
    "items": ["a"]
  }
}

Gotcha

Since single quotes are used to denote field names, regular strings must be enclosed in double quotes. When defining patches in JSON, the double quotation marks needs to be escaped (\").

inc/dec

inc and dec change a numeric value. Each entry in the argument is either an attribute or a JSON path. For each entry, the attribute is looked up, modified and stored. The value may be a positive or negative integer or floating-point value. The operation will fail if target value is not a numeric value, or doesn't exist.

inc increments; dec is the same as inc, except the value is decremented.

Examples

{
  "inc": {
    "stats.visitorCount": 1
  }
}

If it's not certain whether the attribute exists, you can provide a default with setIfMissing:

{
  "setIfMissing": {
    "stats.visitorCount": 0
  },
  "inc": {
    "stats.visitorCount": 1
  }
}

diffMatchPatch

This operation supports robust incremental text patches according to the Google diff-match-patch algorithm, which has wide library support in practically all programming languages in common use. Given the document:

{
  "_id": "dog-1",
  "_type": "someType",
  "aboutADog": "The rabid dog"
}

The following patch applies a diff-match-patch patch to the string:

{
  "patch": {
    "id": "dog-1",
    "diffMatchPatch": {
      "aboutADog": "@@ -1,13 +1,12 @@\n The \n-rabid\n+nice\n  dog\n"
    }
  }
}

The document is transformed to read:

{
  "_id": "dog-1",
  "_type": "someType",
  "aboutADog": "The nice dog"
}

The beauty of diff-match-patch patches is that they allow you to modify huge strings with small patches, and that they compose well, generally giving sane results even when several users or scripts are modifying the same text.

Was this article helpful?