Mutations
How to modify documents directly using the HTTP-api
The mutation API lets you create and modify documents. All requests have to be authenticated.
Gotcha
Please note that validation rules set up on your document types or fields will only run within the studio (client-side). They will not run when using this mutation API (server-side), so you may want to take care of validation separately.
This endpoint accepts the following query-parameters:
returnIdsboolean
(Default
false
) Iftrue
, the id's of modified documents are returned.returnDocumentsboolean
(Default
false
) Iftrue
, the entire content of changed documents is returned.visibilitystring
(default:
sync
) Can be:sync
,async
ordeferred
Ifsync
the request will not return until the requested changes are visible to subsequent queries, ifasync
the request will return immediately when the changes have been committed, but it might still be a second or so until you can see the change reflected in a query. For maximum performance, useasync
always, except when you need your next query to see the changes you made.deferred
is the fastest way to write. It bypasses the real time indexing completely, and should be used in cases where you are bulk importing/mutating a large number of documents and don't need to see that data in a query for several tens of seconds.
curl 'https://<project-id>.api.sanity.io/v1/data/mutate/<dataset-name>' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
--data-binary '{"mutations":[<transactions>]}'
The mutation API is transactional. You may submit an array of mutations and if the operation succeeds you can rest assured that every mutation you submitted was executed. A transaction may look like this:
{
"mutations": [
{"createOrReplace": {
"_id": "person-1",
"_type": "person",
"name": "John Appleseed"
}},
{"createOrReplace": {
"_id": "person-2",
"_type": "person",
"name": "Carrie Anderton"
}}
]
}
The following mutation types exist in Sanity:
create
createOrReplace
createIfNotExists
delete
patch
A create
mutation creates a new document. It takes the literal document content as its argument. The rules for the new document's identifier are as follows:
- If the
_id
attribute is missing, then a new, random, unique ID is generated. - If the
_id
attribute is present but ends with.
, then it is used as a prefix for a new, random, unique ID. For example,foo.
might generatefoo.s4tZYDUyXCCef1YpYu6Js5
. - If the
_id
attribute is present, it is used as-is. _createdAt
and_updatedAt
may be submitted and will override the default which is of course the current time. This can be used to reconstruct a data-set with its timestamp structure intact.
The _type
attribute must always be included and must be a valid Sanity type-name.
The operation will fail if a document by the provided ID already exists.
{ "create": document }
{
"mutations": [
{
"create": {
"_id": "123",
"_type": "cms.article",
"title": "An article"
}
}
]
}
A createOrReplace
mutation attempts to create a new document, and will replace its contents if it already exists. If the document already exists and the type is the same as before, the provided document will act as a set
patch, replacing its entire contents. If the document changes type, it will act as a delete
then create
. If a document has hard references pointing to it, you won't be allowed to change its type with this (or any other) mutation.
{ "createOrReplace": document }
const mutations = [{
createOrReplace: {
_id: '123',
_type: 'cms.article',
title: 'An article'
}
}]
fetch(`https://${projectId}.api.sanity.io/v1/data/mutate/${datasetName}`, {
method: 'post',
headers: {
'Content-type': 'application/json',
Authorization: `Bearer ${tokenWithWriteAccess}`
},
body: JSON.stringify({mutations})
})
.then(response => response.json())
.then(result => console.log(result))
.catch(error => console.error(error))
A createIfNotExists
mutation creates a new document, but will silently fail if the document already exists. It is otherwise identical to create
.
{ "createIfNotExists": document }
{
"mutations": [
{
"createIfNotExists": {
"_id": "123",
"_type": "cms.article",
"title": "An article"
}
}
]
}
Deletes a document. The content should reference a single ID. The operation will be considered a success even if the document did not exist.
{ "delete": { "id": string } }
{
"mutations": [
{
"delete": {
"id": "123"
}
}
]
}
By submitting GROQ-query instead of an id, multiple documents can be deleted in a single mutation.
{
"mutations": [
{
"delete": {
"query": "*[_type == 'feature' && viewCount < 5]"
}
}
]
}
Deletes all documents of type "feature" where the visitCount
is less than 5. See the GROQ-documentation for valid queries.
Gotcha
For the time being you should not delete more than ~1000 documents in one transaction. This will change in the future.
A patch
mutation updates an existing document's contents. A patch will fail if the document does not exist. A patch mutation contains one or more patch operations.
If multiple patches are included, then the order of execution is as follows: set
, setIfMissing
, unset
, inc
, dec
, insert
.
For supported patches, see the patch reference.
{
"mutations": [
{
"patch": {
"id": id,
"ifRevisionID": string,
"set": set,
"setIfMissing": setIfMissing,
"unset": unset,
"inc": inc,
"dec": dec,
"insert": insert,
"diffMatchPatch": diffMatchPatch,
}
}
]
}
{
"mutations": [
{
"patch": {
"id": "123",
"set": {
"name.first": "John"
},
"inc": {
"visitCount": 1
}
}
}
]
}
A patch may include an optional ifRevisionID
field. If the document's current revision ID does not match the provided revision ID, the patch will fail. This can be used for optimistic locking, to make sure that mutations are applied in the exact order expected by the application.
By submitting a query instead of an id, you may patch multiple documents at once. This will reset the score and add a bonus point to any person that has more than 100 points:
{
"mutations": [
{
"patch": {
"query": "*[_type == 'person' && points >= 100]",
"dec": {
"points": 100
},
"inc": {
"bonuses": 1
}
}
}
]
}