Atomic set and increment operators for GraphQL mutations

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.

TL;DR:

  • Hasura allows you to update multiple objects in one shot using a powerful where argument which allows you to create a boolean filter to select the objects to be updated
  • Hasura supports a set operator to set or replace an existing value
  • Hasura supports an increment operator 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 set the 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, _set , _inc and where.

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://blog.hasura.io/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

Using the "_set" operator

The _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:

Using 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 _prepend, _append, _delete_key, _delete_elem, and _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://blog.hasura.io/postgres-json-and-jsonb-type-support-on-graphql-41f586e47536


Hasura is an open-source engine that gives you realtime GraphQL APIs on new or existing Postgres databases, with built-in support for stitching custom GraphQL APIs and triggering webhooks on database changes.