As GraphQL specification states, mutations are used to mutate (modify) data, and in the context of MIP, that means that we can mutate records in the Salesforce environment. Therefore, with mutations we can insert, upsert, update or delete the records from our Salesforce org.
If we look back for a moment to the example Query from the previous section of building a GraphQL query:
|
|
we see that there is no information on what type of operation is being executed. That is because the Query is always the default operation that does not need to be explicitly listed. But now when we try to build Mutations, the keyword mutation
is required to be inserted at the beginning of the document.
MIPs GraphQL mutation syntax, for every type of mutation request, is the following:
mutation {
typeOfMutationRequest_ObjectAPIname(records:[{fieldAPIname: "value"}]) {
fieldAPInameToReturn
}
}
mutation {
typeOfMutationRequest_ObjectAPIname(records:[
{fieldAPIname: "value1"},
{fieldAPIname: "value2"}
]) {
fieldAPInameToReturn
}
}
mutation {
typeOfMutationRequest_ObjectAPIname(records:[
{fieldAPIname: "value1"},
{lookupAPIname: {
fieldAPIname:"value2"
}
}
]) {
fieldAPInameToReturn
}
}
mutation
is one of the three types of operation keywords which can be: query, mutation or subscriptiontypeOfMutationRequest
is one of the available mutation types which can be: insert, upsert, update or deleteObjectAPIname
is the API name of the Object that we are mutating. (Making some mutation requests from 2.)object
or objects
is just a fixed input object name located in the argument that informs our MIP parser on how many records are we mutating - one if we write object, or more than one if we write objectsfieldAPIname
is the API name of the field we are mutatingvalue
is the value of the field from 5.fieldAPInameToReturn
is the API name of the field we need to be returned as the result. Field values that are returned are only those fields that are the result of the mutation operation request itself. The result of mutation is record or records that are created.Apart from the obvious mutation result, which is simply the record we mutated (for example inserted), notice the fieldAPInameToReturn
in the previous building mutations section. That means that apart from inserting, we can immediately get any fields, or child records if there are any, back from that record as well.
That is because the mutation is by the GrapQL definition a write, followed by a fetch. One may wonder, why would we want to fetch the data we just mutated. We already know the data we are mutating, why would there need to retrieve it immediately after. Isn't that just redundant and unnecessary duplication?
The short answer is no. It most definitely is not.
There are numerous reasons why that may be the case, so let's name a few in case of inserting records:
Mutations are executed through one transaction. That means that every change is wrapped and rollbacked if any error occurs.
For example, in the case of inserting child records together with the parent, even if the child record is successfully inserted, and the error occurs later when inserting parent - everything will be rollbacked to the state before the mutation execution started.
Let's imagine we want to insert two Contact records, with FirstName and LastName of Sean Forbes and Jack Rogers respectively. By following instructions from building mutations, we would construct the following mutation:
|
|
Notice that Id, FirstName, and LastName are requested to be fetched by this mutation.
With the mutation above, we have inserted two records and retrieved the inserted data and their new Id.
And in the case of inserting only one record, mutation will look like this:
|
|
Inserting records that have lookup to other records is also possible.
We can either provide the Id as the value of the field lookup relationship name, or just create a new record in that place by following the same syntax. By writing lookup relationship name, MIP will know what object should be created.
In this example, we are creating two Contacts, but also populating the second one with the new lookups to the Account and Contact. So in the one mutation request, we are defining four records that will be inserted in the optimal number of insert calls.
|
|
If the lookup records are already created, we can simply pass the Id as the value, and not bother with creating one.
|
|
There is no limit as to how many records in one mutation can be created or how deeply nested the lookup relationship fields can be.
Using the upsert operation, you can either insert and / or update an (existing) records in one call.
MIP will first try and insert the records. If if "fails" (if there is ID present as the field name), it will then try and update it.
Therefore, to determine whether a record already exists, the upsert statement uses only the record’s ID as the key to match records.
If the ID is not present, then a new object record is created.
If the ID is present, then the existing object record is updated.
For example, let's consider that we already have one Contact record of Sean Forbes and we want to update the phone number of Sean, but insert Jack Rogers into Contacts as well.
|
|
In the first list element (Sean Forbes) we have provided an Id, so the MIP knows that it can only update that record.
In the second list element (Jack Rogers), we did not provide an Id, so the MIP inserts record with specified attributes.
But what if we don't necessarily know the Id of the record or want to update more than one record that matches some criteria?
In that case - see mutation Update below.
In the upsert mutations, we saw that the update will execute only if there is an Id present.
Update mutations on the other hand are using filter keyword and / or any other available (just as it is used in the GraphQL Queries) to find the records we want to update - without specifically knowing their Ids.
|
|
In the mutation above, we have selected all of the Contacts that have FirstName Byron and LastName Bernstein, born on the date greater than 2000-09-11 and have updated the LastName of such Contacts to BernsteinJR. Keep in mind that there can be multiple records of those values.
The new input object we encountered here is set. Set is used only in mutation update when we want to update the field values.
The same functionality arrives with mutations delete operation. Difference is only that we are not setting anything, so we just need to find the records and MIP will do the rest.
|
|
In the mutation above, we deleted all of records that have Sean as FirstName and Forbes as LastName and the result is empty Contact list meaning that now no contact can be found that match that criteria.
If the delete was unsuccessful, there would still be Contact record of Sean Forbes in the resulting data map.