# Storage Collections Versioning

**URL:** <https://forum.heroiclabs.com/t/storage-collections-versioning/3898>\
**Category:** Game Design\
**Tags:** server-framework, typescript\
**Created:** [May 25, 2023, 6:56pm UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898 "2023-05-25T18:56:47Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Albertcleetus](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/albertcleetus/32/603_2.png) [@Albertcleetus](https://forum.heroiclabs.com/u/Albertcleetus)\
**Post date:** [May 25, 2023, 6:56pm UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/1 "2023-05-25T18:56:47Z")

</div>

Hello everyone,  
Recently we started to do some changes in our game, that made some of the saved collections structures. Not fully obsolete but some of the fields had change.  
For example like this: [Json data]  
example:  
Collection : character\_inventory  
Key : character\_access

In create time :  
{  
“character1\_isUnlocked”: false,  
“character2\_isUnlocked”: true,  
“character3\_isUnlocked”: false,  
“character4\_isUnlocked”: true,  
“character5\_character”: false,  
“character6\_isUnlocked”: false,  
“character7\_isUnlocked”: false,  
“character8\_isUnlocked”: false,  
“character9\_isUnlocked”: true  
}

And after game Updates : we Introduced new character so I changed collection json as:

After Update time :  
{  
“character1\_isUnlocked”: false,  
“character2\_isUnlocked”: true,  
“character3\_isUnlocked”: false,  
“character4\_isUnlocked”: true,  
“character5\_character”: false,  
“character6\_isUnlocked”: false,  
“character7\_isUnlocked”: false,  
“character8\_isUnlocked”: false,  
“character9\_isUnlocked”: true,  
“character10\_isUnlocked”: false  
}

In create time , I will init these type collections in

const afterCreate: nkruntime.AfterHookFunction\<  
nkruntime.Session,  
nkruntime.AuthenticateEmailRequest

> = function (  
> ctx: nkruntime.Context,  
> logger: nkruntime.Logger,  
> nk: nkruntime.Nakama,  
> data: nkruntime.Session,  
> req: nkruntime.AuthenticateEmailRequest  
> ){  
> if (data.created) {  
> let user\_id = ctx.userId;  
> let character\_access = {ABOVE JSON}  
> let character\_inventory: nkruntime.StorageWriteRequest = [  
> {  
> collection: “character\_inventory”,  
> key: “character\_access”,  
> userId: user\_id,  
> value: JSON.parse(character\_access),  
> },  
> ];  
> try {  
> nk.storageWrite(character\_inventory);  
> } catch (error) {  
> logger.info(“error”);  
> }  
> else  
> return; // if account is not new return  
> };

[In create time Json] at that time authenticating users had character1…character9 in collection.

After the update I will introduced new “character10” field or add a new object for the wallet and user collections…  
Server code updates and Collection change, Fields add … It will effect to Newly authenticated user,

how will I migrate or add this collection and wallets fields and changes to old user also…

I don’t know we can call this as storage collection versioning, I feel like that or otherwise I need to change the flow?

---

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/tom/32/676_2.png) [@tom](https://forum.heroiclabs.com/u/tom)\
**Post date:** [May 30, 2023, 8:16am UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/2 "2023-05-30T08:16:58Z")

</div>

One simple solution here is to simply assume that if the key does not exist in the user’s storage object then they do not have the character. This will allow you to add as many characters as you like later down the line and the logic will work the same.

e.g. for a player who has unlocked character 1, 2 and 5 their object will look as follows:

```auto
{
  "character1_isUnlocked": true,
  "character2_isUnlocked": true,
  "character5_isUnlocked": true
}

```

Here you use the absence of the key as an implicit `false` value.

This avoid the needs for migrating your data and once the logic has been added to the game server/client existing players with the current storage object structure will continue to work as normal (they won’t have character 10).

Where possible it is best to try and avoid breaking the backwards compatibility of your data structures. I would not recommend pre-planning a data migration system.

---

<div class="post-metadata">

**Author:** ![Albertcleetus](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/albertcleetus/32/603_2.png) [@Albertcleetus](https://forum.heroiclabs.com/u/Albertcleetus)\
**Post date:** [May 30, 2023, 10:43am UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/3 "2023-05-30T10:43:20Z")

</div>

That’s Okay, but you see…  
I updated the collection of character\_inventory to add new field with new character name: example as follows  
{  
“character1\_isUnlocked”: false,  
“character2\_isUnlocked”: true,  
“character3\_isUnlocked”: false,  
“character4\_isUnlocked”: true,  
“character5\_character”: false,  
“character6\_isUnlocked”: false,  
“character7\_isUnlocked”: false,  
“character8\_isUnlocked”: false,  
“character9\_isUnlocked”: true,

“character10\_isUnlocked”: false,  
“character11\_isUnlocked”: false,  
}

“character10\_isUnlocked” and “character11\_isUnlocked” are new character or fields.  
this storage change will effect to the newly authenticated client as per above code.

How will i update this to old clients also? @tom

---

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/tom/32/676_2.png) [@tom](https://forum.heroiclabs.com/u/tom)\
**Post date:** [May 30, 2023, 10:50am UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/4 "2023-05-30T10:50:08Z")

</div>

I understand that `character10_isUnlocked` is a new field. My proposal is that it shouldn’t matter for old clients. Your server or client logic can check for the existence of the key `character10_isUnlocked` and if it doesn’t exist they can safely assume the player hasn’t unlocked the character yet (i.e. the value is implicitly `false`).

When the player eventually unlocks the character, you simply add the key with a value of `true` to their `character_inventory` storage object (or update the value to `true` if the key does exist).

To expand on this concept further, let’s assume we’re working with a standard player’s inventory where they can store items such as a sword, shield, potion etc.

You may represent the player’s current inventory like this:

```auto
{
  "items": [
    { "id": "sword", "quantity": 1 },
    { "id": "potion", "quantity": 10 }
  ]
}

```

In this example the player is assumed to not have the `shield` item yet because it doesn’t exist in their inventory storage object.

The same concept can be applied to your character unlock mechanic.

---

<div class="post-metadata">

**Author:** ![Albertcleetus](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/albertcleetus/32/603_2.png) [@Albertcleetus](https://forum.heroiclabs.com/u/Albertcleetus)\
**Post date:** [May 30, 2023, 11:23am UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/5 "2023-05-30T11:23:42Z")

</div>

OK, then  
what about the storage. after the game update I need to update new wallet field.? @tom

And also in my logic some of other collections like avatars or skins of the user.  
That is actually i done initially in server and after game starts , All the Skins and avatars in the game will loaded to client with corresponding key values like true or false.  
how will i change this collections. [To add new avatar and skin to the game! Asset will add in client side and the index or item is want to add in server for init , according to this game starts all the avatars will load to client]

---

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/tom/32/676_2.png) [@tom](https://forum.heroiclabs.com/u/tom)\
**Post date:** [May 30, 2023, 11:39am UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/6 "2023-05-30T11:39:22Z")

</div>

In this scenario I would advise having a storage object that is defined as a form of global (public read / no write) configuration that clients can access and update their local version accordingly.

For example, you could create a configuration object that lived in a `config` collection that looked like this:

```auto
{
  "availableCharacters": ["character1", "character2", "character3", ...],
  "availableSkins": ["skin1", "skin2", "skin3", ...],
  "availableAvatars": [...],
}

```

The client could read this configuration file and update the UI appropriately. When you want to add a new character to the game, you add it to the `availableCharacters` array. The client will then read this the next time it launches.

This way you do not need to explicitly keep a record up to date for every player in your game to determine what they **don’t have** , and instead you only update their records when they **do have** something.

---

<div class="post-metadata">

**Author:** ![Albertcleetus](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/albertcleetus/32/603_2.png) [@Albertcleetus](https://forum.heroiclabs.com/u/Albertcleetus)\
**Post date:** [May 30, 2023, 11:46am UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/7 "2023-05-30T11:46:24Z")

</div>

Thank you for the advice.

OK I will try this implementation as per you said @tom

What about the player wallet - updating of field ?

---

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/tom/32/676_2.png) [@tom](https://forum.heroiclabs.com/u/tom)\
**Post date:** [May 30, 2023, 11:49am UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/8 "2023-05-30T11:49:44Z")

</div>

No problem.

Player wallet should act in a similar way. If your game client is checking for the existence of a player’s `gems` amount but their wallet looks like this:

```auto
{
  "coins": 12,
  "stars": 5
}

```

Then the client should assume the player has 0 `gems`. You only need to add the `gems` key to their wallet once the player actually receives some.

If you are adding a new virtual currency to your game and you want every player to start with some (e.g. `100 gems`) then you can do this with an [After Hook](https://heroiclabs.com/docs/nakama/server-framework/introduction/hooks/#after-hooks) when they next authenticate.

---

<div class="post-metadata">

**Author:** ![Albertcleetus](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/albertcleetus/32/603_2.png) [@Albertcleetus](https://forum.heroiclabs.com/u/Albertcleetus)\
**Post date:** [May 30, 2023, 11:55am UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/9 "2023-05-30T11:55:18Z")

</div>

@tom Can you given an example for adding the wallet new key?  
i only see like this let changeset = { gems: gemChange};  
to change the values of gem field

---

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/tom/32/676_2.png) [@tom](https://forum.heroiclabs.com/u/tom)\
**Post date:** [May 30, 2023, 12:06pm UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/10 "2023-05-30T12:06:58Z")

</div>

The changeset is all you need. Nakama is smart enough to add or update the value in the player’s wallet appropriately.

---

<div class="post-metadata">

**Author:** ![Albertcleetus](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/albertcleetus/32/603_2.png) [@Albertcleetus](https://forum.heroiclabs.com/u/Albertcleetus)\
**Post date:** [May 30, 2023, 5:28pm UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/11 "2023-05-30T17:28:25Z")

</div>

You mean In changeset i can add the new field also?  
Like old wallet :  
{  
“coins”: 12,  
“stars”: 5  
}  
To add new wallet data : let changeset = { gems: 0};  
{  
“coins”: 12,  
“stars”: 5,  
“gems”:0  
}

---

<div class="post-metadata">

**Author:** ![tom](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/tom/32/676_2.png) [@tom](https://forum.heroiclabs.com/u/tom)\
**Post date:** [June 1, 2023, 8:52am UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/12 "2023-06-01T08:52:08Z")

</div>

Yes, that’s correct.

---

<div class="post-metadata">

**Author:** ![Albertcleetus](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.heroiclabs.com/albertcleetus/32/603_2.png) [@Albertcleetus](https://forum.heroiclabs.com/u/Albertcleetus)\
**Post date:** [August 12, 2023, 8:31pm UTC](https://forum.heroiclabs.com/t/storage-collections-versioning/3898/13 "2023-08-12T20:31:45Z")

</div>

Issue . here. I can’t solve this logic
