How to use DataStore2 - Data Store caching and data loss prevention

This sounds like a problem with race conditions in your own code. You can solve this by not yielding in between getting their points and setting them. You can also just use :Increment.

Hey, I have a question that I couldn’t find the answer to in the documentation.

If I use :Get(default) and it returns the specified default value, does it save that default value to the cache? I was having some problems where I called :Get in two places, and one had a different default value than the other. The one that ran first seemed to cache the default value in DS2, so the second one also had that value despite having a different default value specified.

I didn’t :Set that store anywhere in the game, so the caching seems to have been caused by that. I know that getting a store with two separate default values probably isn’t a good idea, and it was just an oversight on my part. Once I reset data and specified the same default value in both places it all worked. Just asking to make sure this is what actually caused the problem and not something else.

Hi, a quick question.
I have a table with inside a table element another table, like this:

local emptyInventory = {
	["Trails"] = {
		["Rainbow"] = false;
		["Red"] = false;
        --more trails
	};
	["Pets"] = {
		["Bear"] = false;
		["Beth"] = false;
        --more pets
	};
}

And I am using :GetTable(emptyInventory). But I found out that when adding more entries in a subtable, it won’t get updated, which will normally do with more entries in the ‘headtable’. Is there a way to make the complete table update when you add more entries, or is it recommended to split in multiple datastores (such as “emptyTrailInventory” and so on).

Thanks in advance!

Hi, I have a question. Does Datastore2 save each time you do :Set or does it only save when you leave the game?

As @kampfkarren said:

“The normal way of doing data stores is to keep a cache somewhere of a player’s data (such as in a folder or using leaderstats), then saving when the player leaves. It is wrong, however, to use DataStore2 this way. DataStore2 is built to be used whenever your data actually changes. You shouldn’t invoke DataStore2 in PlayerRemoving at all. Don’t worry, :Set will never error or do API calls, it’s all cached. DataStore2 will save the player’s data before they leave.”
(DataStore2)

So it saves your data when your data changes, not when the player leaves.

1 Like

I’m not sure, though it’s weird to me that you would supply two different default values in the first place? Without looking, I believe that it does set to cache.

1 Like

You can just do it by hand, as in write your own code to deal with nested tables.

Yeah that would make sense to me. I used two different default values in two different places as a mistake, I changed it one place and forgot to change it in the other. Just making sure that this is what was actually causing my problem and not something else.

1 Like

I dont know about this but i’m trying to set number value to number but it does not work

and here is the code and the error

  17:11:14.257 - Invalid at input.TrailColor because: Invalid type (Instance)
  17:11:14.259 - Invalid data while saving

Server code:

local DataStore2 = require(game.ServerStorage:WaitForChild("MainModule"))

DataStore2.Combine("MasterKey","TrailColor")

function plrAdd(plr)
	local TrailData = DataStore2("TrailColor",plr)
	
	local TrailColor = Instance.new("NumberValue")
	TrailColor.Parent = plr
	TrailColor.Name = "TrailColor"
	TrailColor.Value = TrailData:Get(0)
	
	TrailData:OnUpdate(function(value)
		TrailColor.Value = value
	end)
end

for _, plr in pairs(game.Players:GetPlayers()) do
	plrAdd(plr)
end

game.Players.PlayerAdded:Connect(plrAdd)



game.ReplicatedStorage.ChangeTrail.OnServerEvent:Connect(function(plr,number)
	if plr then -- if they exist
		local TrailData = DataStore2("TrailColor",plr)
		
		if TrailData:Get(0) then
			TrailData:Set(number) -- if 8 sent then sets to 8
		end
	end
end)

Client Code:

local plr = game.Players.LocalPlayer

script.Parent.MouseButton1Click:Connect(function()
	game.ReplicatedStorage.ChangeTrail:FireServer(plr,1)
end)

im trying to add the number from the client on the server and it says invalid type (instance)

But Im Setting the value to a number from the client on the server

is there any good answers to this issue?

You can’t save instances to data stores, only numbers, strings, and tables that just contain numbers and strings.

Your LocalScript has a Remote Event syntax error. Not a DataStore or a DataStore2 issue.

Should be

game.ReplicatedStorage.ChangeTrail:FireServer(1)

as :FireSever() already includes the calling Player as the first parameter.

2 Likes

Here’s a possible solution, which I use.

local oldTable = DataStore2:GetTable("datastore name",player) -- gets the table/plr inventory, and stores it
table.insert(oldTable.Trails,["Green"] = true) -- inserts the new entry
DataStore2:Set("datastore name",player,oldTable) -- sets the data to same table, plus our entry

How do I load the data from the deserialization onto the key? Every time I do it, it loads the default values instead. I added another :Get() function in hopes of it retrieving the data for the desierialized key, but its not working. :confused:

1 Like

Could you explain which parts of your script are not working? I can’t understand what you are trying to say here, unfortunately.

1 Like

sure. So, the deserialization-- well to be clear, i’m still trying to understand how the deserialization and serialization works entirely. My knowledge so far is that it serializes the keys into number keys instead, then fetches the name of the key from a list. Correct me if im wrong. Of this i have succeeded.

I fetched the names of the keys via the deserialization, but… i can’t figure out how the value saved gets attached to the key. I tried what the documantion said first, and just put a true value behind it, hoping that it would automatically change it when returned, but it didnt, it set the value to true entirely. Then i started experimenting with other things, and i cant retrieve my changed data that I had saved (properly) before I left the game and came back, it keeps appearing as the default data.

My issue in short is I’m not sure how to attach the saved value to the respective keys that are being deserialized.

Im sorry, I was only able to understand some parts. Hopefully this clears it up for you.

Say, we have 2 functions, 1 to serialize, and another to deserialize.

local function Serialize(item)
       
end

local function Deserialize(key)

end

Now, on top of that, we have a dictionary that contains the keys and values, like so.

local Dictionary = 
{
    {key = 1,value = "Doge Head Of Awesomeness"}
}

What the Serialize() function does, is to find a key, that matches a given value, so say we ran this:

local Dictionary = 
{
    {key = 1,value = "Doge Head Of Awesomeness"}
}

local function Serialize(item)
      local key = nil -- what this function returns, which is the serialized item key
      for index,data in pairs(Dictionary) do -- loops thru the dictionary
             if data.value == item then  -- if the value of the current data that we are looping thru matches what we are looking for, which is the item
                    key = data.key -- sets the key to the serialized key
                    break -- breaks the loop
             end
      end
      return key
end

local serialized_key = Serialize("Doge Head Of Awesomeness") -- = 1

Then serialized_key would be equal to 1. Deserialize works vice versa, so if you ran Deserialize(serialized_key) then it would return "Doge Head Of Awesomeness".

 local function Deserialize(key)
      local item = nil -- what this function returns, which is the deserialized item
      for index,data in pairs(Dictionary) do -- loops thru the dictionary
             if data.key == key then  -- if the value of the current data that we are looping thru matches what we are looking for, which is the item
                    item = data.value -- sets the key to the serialized key
                    break -- breaks the loop
             end
      end

      return item
end
local deserialized_item = Deserialize(serialized_key) -- "Doge Head Of Awesomeness"

Now, say you wanted to save stuff to an inventory. You would store the serialized key of an item into a DataStore, which can then be deserialized with Deserialize(), and used in the game.

EG:

"Timmy just bought Doge Head Of Awesomeness. He leaves the game, and Serialize() is called to serialize his data, which is the Doge Head Of Awesomeness. "

"Upon joining the game the next day, Deserialize() is called to deserialize his data, so that the game scripts can read his data more easily. "

"A script then checks the deserialized data of Timmy, and if they find “Doge Head Of Awesomeness”, then they put that item on his avatar. "

TD;LR: saved serialized data looks something like this:

{value = 1,owned =  true}

and deserialized data looks something like this:

{value = "Doge Head Of Awesomeness",owned = true}

Scripts can then check the deserialized data, like so.

local plrSavedData = datastorename:Get()
 local plrOwnsDogeHead = false
for _,savedData in pairs(plrSavedData) do
       if (savedData.value == "Doge Head Of Awsomeness") and (savedData.owned) then
              plrOwnsDogeHead = true
       end 
end

if (plrOwnsDogeHead) then
       -- whatever happens if they own the doge head
end 

Sorry for this long post, but I hope this clears it up for you. Have a nice day!

1 Like

Thank You. Very much. :1st_place_medal:

Did you solve it?

(30 charsss)

I did. My problem was I was indexing the wrong thing to serialize. I was serializing the key instead of the value, which was why it was coming out wierdly. :slight_smile: (Cuase I’m silly.) (From here I think i can figure out doing deserializing and serializing with layered dictionaries, values with tables in them. Cause I have a lot of that.

Awesome. Good luck with your game/project!

1 Like