# Atomic operators for database writes?

**URL:** <https://forum.heroiclabs.com/t/atomic-operators-for-database-writes/6048>\
**Category:** Runtime Framework\
**Tags:** server-framework, typescript\
**Created:** [February 27, 2025, 3:25am UTC](https://forum.heroiclabs.com/t/atomic-operators-for-database-writes/6048 "2025-02-27T03:25:17Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![KamilDev](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/kamildev/32/2454_2.png) [@KamilDev](https://forum.heroiclabs.com/u/KamilDev)\
**Post date:** [February 27, 2025, 3:25am UTC](https://forum.heroiclabs.com/t/atomic-operators-for-database-writes/6048/1 "2025-02-27T03:25:17Z")

</div>

Coming from MongoDB, one of the nice things I discovered were the [atomic operators](https://www.mongodb.com/docs/manual/core/write-operations-atomicity/). For example:

### An excerpt example from the MongoDB docs:

Consider a collection with this document:

```auto
db.games.insertOne( { _id: 1, score: 80 } )

```

Consider if these update operations occur concurrently:

```ts
// Update A
db.games.updateOne(
   { _id: 1 },
   {
      $inc: { score: 10 }
   }
)
// Update B
db.games.updateOne(
   { _id: 1 },
   {
      $inc: { score: 20 }
   }
)

```

After one update operation completes, the remaining operation still matches the query predicate `{ _id: 1 }`. However, because the operations modify the current value of `score`, they don’t overwrite each other. Both updates are reflected and the resulting `score` is `110`.

* * *

Does Nakama support such atomic operators?

From my understanding, Nakama will error out if conflicting database values are attempted to be written (using an internal `version` field).

However, the ability to use atomic operators should allow for smoother cases and avoid retrying an entire function for conflicting database writes that could be resolved with atomic operators.

The only thing I found in Nakama that has a similar approach is [Virtual wallet](https://heroiclabs.com/docs/nakama/concepts/user-accounts/#virtual-wallet), but I need it for other cases too.

---

<div class="post-metadata">

**Author:** ![sesposito](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/sesposito/32/2594_2.png) [@sesposito](https://forum.heroiclabs.com/u/sesposito)\
**Post date:** [February 27, 2025, 11:12am UTC](https://forum.heroiclabs.com/t/atomic-operators-for-database-writes/6048/2 "2025-02-27T11:12:36Z")

</div>

Hello @KamilDev,

As you mention, Nakama uses Optimistic Concurrency Control (OCC) making use of the version field. If the update tries to overwrite an “unseen” change, it’ll fail.

There’s no concept of atomic operators, if you’d like to achieve something similar it is possible but you’d have to use custom SQL.

Example:

```auto
INSERT INTO 
    storage AS s (collection, "key", user_id, "value", version, "write")
VALUES
    ('counter', 'count', $1, '{"count":1}'::JSONB, md5('{"count":1}'::TEXT), 0)
ON CONFLICT
    (collection, "key", user_id)
DO
    UPDATE SET
        version = md5(excluded."value"::TEXT),
        "value" = jsonb_build_object('count', (s."value"->>'count')::INT + 1)

```

docs: [PostgreSQL: Documentation: 16: 9.16.&nbsp;JSON Functions and Operators](https://www.postgresql.org/docs/16/functions-json.html)

The peril of writing custom queries is optimization and correctness, the Nakama provided APIs ensure that indices are used correctly and that queries will perform optimally. The OCC model also avoids exposing transactions because using them incorrectly can also cause severe performance issues at scale. This is why we recommend against writing custom queries unless it’s truly warranted and the queries are sound.

In practice, the OCC model works well because updates for a given user should rarely cause parallel writes to the same row unless the client is acting incorrectly.

For shared objects, one must be careful about frequency of updates - globally shared objects (owned by the global nil user) that are updated very frequently are often a bad idea and can cause issues at scale as they cause a lot of contention on that row.

Best.

---

<div class="post-metadata">

**Author:** ![KamilDev](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/kamildev/32/2454_2.png) [@KamilDev](https://forum.heroiclabs.com/u/KamilDev)\
**Post date:** [March 8, 2025, 10:58pm UTC](https://forum.heroiclabs.com/t/atomic-operators-for-database-writes/6048/3 "2025-03-08T22:58:59Z")

</div>

Does Nakama support transactions, or what would the suitable way to do it Nakama?

Lets say I have a function that lets players gift an energy point to a different player, and then they also get rewarded 100 gold. Like this:

1. Get receiver player data
2. Increment energy by 1, save to DB
3. Get this current player data
4. Increment gold by 100, save to DB

If an error happens halfway, how should I handle it? With transactions, I think it would safely discard and revert all the changes, so the function can be retried if needed.

Otherwise, it could end up like the player gifted the energy, but due to error, they never received their 100 gold reward. We can’t simply retry the function as it would give an extra energy point to receiver player.

---

<div class="post-metadata">

**Author:** ![sesposito](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/sesposito/32/2594_2.png) [@sesposito](https://forum.heroiclabs.com/u/sesposito)\
**Post date:** [March 10, 2025, 10:58am UTC](https://forum.heroiclabs.com/t/atomic-operators-for-database-writes/6048/4 "2025-03-10T10:58:56Z")

</div>

The [multiUpdate](https://heroiclabs.com/docs/nakama/server-framework/go-runtime/function-reference/#MultiUpdate) API performs updates to multiple objects/wallets/accounts transactionally.
