Storage engine structure

Hello.
I need some help to understand how i would go about the data stored the storage engine.

For instance, i do have some data that belongs to describe a Player.

As how it is now i have a collection called “player_data” and a key value for each value stored in the engine:

collection: “player_data”, key: “position”
collection: “player_data”, key: “username”
collection: “player_data”, key: “exp”

is this a valid thing to do? or is it preferable to store everything under one key?

Thanks! :slight_smile:

Hi @gruset. You ask a great question because I’ve noticed more and more game teams that seem to separate out each storage object to handle a single value rather than a complex JSON object. This is not how we envisaged the storage engine would be used with Nakama server so let me share some example data structures from a game project we worked on with a studio.

I hope it will help to share how we think is the most optimal way to store data for players with Nakama.

  • collection = economy, key = inventory
{
  "consumables": {
    "spawner_A": {
      "count": 40,
      "owned_time": 1636888665
    },
    "spawner_B": {
      "count": 0,
      "owned_time": 1636888665
    },
    "spawner_C": {
      "count": 24,
      "owned_time": 1636888665
    }
  },
  "collectables": {}
}

We implemented an inventory system which uses the concept of both collectables and consumables which exist for the user. These could be objects like swords, shields, collectable cards or really any entity which is owned by the user but can be accumulated, spent, and/or traded.

  • collection = economy, key = donations
{
  "donations": {
    "team_help_tickets": {
      "count": 4,
      "claim_count": 4,
      "expire_time": 1637101354,
      "contributors": {
        "16cafe3c-3ea7-4fb2-8d74-4bab45304762": {
          "count": 1,
          "update_time": 1637090139
        },
        "2e1ac665-ffd8-4014-a83e-b28e34b4b2ac": {
          "count": 1,
          "update_time": 1637091079
        },
        "f623189c-98fd-4302-bf6b-dc11d5343766": {
          "count": 1,
          "update_time": 1637089806
        }
      }
    }
  }
}

This is your typical donation system where users in the same guild or team can gift objects to each other in exchange for rewards. We track how much contribution each user has made to the current user’s donation request.

  • collection = progression, key = achievements
{
  "achievements": {
    "R1_TASK1": {
      "count": 1,
      "claim_time": 1639493455,
      "create_time": 1639493455,
      "update_time": 1639493455
    },
    "R1_TASK2": {
      "count": 1,
      "claim_time": 1639495509,
      "create_time": 1639495509,
      "update_time": 1639495509
    },
    "R1_TASK3": {
      "count": 2,
      "claim_time": 1639497209,
      "create_time": 1639497209,
      "update_time": 1639497209
    }
  }
}

This is your typical achievement system where the user has to obtain some count of progress towards the achievement before its unlocked and they can optionally obtain a reward for it.

A few other notes about the example data you showed:

collection: “player_data”, key: “position”
collection: “player_data”, key: “username”
collection: “player_data”, key: “exp”

The user account in Nakama for each player already handles the username field and has a separate field called display_name (same as Steam API) for situations where the name can be the same as other users. You shouldn’t need to store that separately ever in the storage engine.

Hope this helps.

1 Like

is this a valid thing to do? or is it preferable to store everything under one key?

I forgot to answer your specific question. :slight_smile:

The answer is really to store everything under a single key but only for logically related bits of data. For example achievements are not part of the player’s inventory which means they make sense as separate storage objects.

Hello there and thank u for ur answer! :slight_smile: I fully understand what u are saying, and i assume its the way to go! Though, one thing that comes to mind:

What if i have to store just one property in the while table. For instance, i want to save the state of a players position. Thats a read and a write operation. instead of just one write.

First we have to read the whole table. Get the right property to modify, in our case the position. then store the updated table once again.

Wouldnt it be better to seperate the data as mentioned above? :slight_smile:

Take care!
/G