When using GraphQL, writes or updates to data are made via mutations. In this post we will discuss the update mutations and related operators that are available on the Hasura GraphQL Engine.
- Hasura allows you to update multiple objects in one shot using a powerful
whereargument which allows you to create a boolean filter to select the objects to be updated
- Hasura supports a
setoperator to set or replace an existing value
- Hasura supports an
incrementoperator to atomically increment numerical values by a given amount to prevent common race conditions where multiple clients are incrementing the same attribute
- Hasura supports native JSON/JSONB operators that you can use to modify attributes in a JSON/JSONB value of a postgres column without needing to
setthe full JSON value
Schema and generated mutations
Let’s consider the following schema for our example:
When the above tables are tracked in Hasura GraphQL Engine, it will automatically generate the following update mutations:
As you can see above, there are 3 key arguments in the update mutation,
where is a boolean expression, which is mandatory.
where will help you select the rows on which the mutation is to be applied. Otherwise the update mutation will have to be applied for all rows in the table or only on one particular row, either of which are not particularly flexible options. You can read more about “bulk update” mutations here: https://hasura.io/blog/bulk-update-and-delete-mutations-in-graphql-6568f47ad0b9
You can look into the generated mutations in detail at: https://hge-update-mutations.herokuapp.com/console
the "_set" operator
_set operator “sets” the value of one or more columns of a row by replacing the existing value. Consider 2 illustrative examples below:
Let’s say we want to update the title and content of an article that the user is editing. We can run the following GraphQL query using the
_set operator (assuming we know the id of the article) :
If we want to update all articles of an author, i.e. update data using nested objects’ fields, our query would be like the following:
the "_inc" operator
The _inc operator atomically increments the existing value of one or more columns by a given amount. This operator is only for columns that have a “numeric” type, like integer, numeric, float, double etc.
Let’s say we want to update the likes of an article. As it is a numeric field, we can take advantage of the
_inc operator. We can run the following GraphQL query (assuming we know the id of the article) :
Why do we need “_inc”?
The advantage of using
_inc is we can avoid race conditions.
If we were using
_set directly — fetch previous likes, increment them on the client, and then run a set query with the new value — which can lead to race conditions when two clients simultaneously fetched the same likes and tried to update. One of our likes will be lost. As the
_inc query is guaranteed to run atomically, we know that using that we will not run into race conditions.
Using mutations to update JSON/JSONB data
Hasura GraphQL Engine has first-class support for updating JSON/JSONB data in your Postgres tables. You don’t have to form the JSON in your client and use
_set . You can directly use any of
_delete_at_path operators to update nested keys and values in your JSON data.
You can read more about these operators in this blog: https://hasura.io/blog/postgres-json-and-jsonb-type-support-on-graphql-41f586e47536