Trying to save table to Datastore

Hello,
I thought of making a simple-ish example of saving a table to a datastore before going on to do the good stuff.
Could someone tell me what I am doing wrong here? - It never prints out anything no matter how much I rejoin.
Yes, I have API settings enabled etcetc.

local DS = game:GetService("DataStoreService"):GetDataStore("TestDataStore")
local table1 = {Adam = "Sandler", Lionel = "Messi"}

game.Players.PlayerAdded:Connect(function(plr)
	wait()
	local plrkey = "id_"..plr.userId
	local savetable = table1
	local GetSaved = DS:GetAsync(plrkey)
	if GetSaved then
		savetable.value = GetSaved[1]
	else
		DS:GetAsync(plrkey, table1)
		print(GetSaved[1].Lionel) --Messi
	end
end)


game.Players.PlayerRemoving:Connect(function(plr)
	DS:SetAsync("id_"..plr.userId, table1)
end)

You should do this:

local DS = game:GetService("DataStoreService"):GetDataStore("TestDataStore")
local table1 = {Adam = "Sandler", Lionel = "Messi"}

game.Players.PlayerAdded:Connect(function(plr)
	wait()
	local plrkey = "id_"..plr.UserId
	local savetable
	local GetSaved = DS:GetAsync(plrkey)
	if GetSaved then
		savetable = GetSaved
        print(GetSaved.Adam, GetSaved.Lionel)
	else
		DS:SetAsync(plrkey, table1)
	end
end)


game.Players.PlayerRemoving:Connect(function(plr)
	DS:SetAsync("id_"..plr.UserId, table1)
end)

To point out the errors in the op:

  1. It should be UserId, and not userId
  2. You shouldn’t do GetSaved[1] because the table is not saved as an array - it’s a dictionary. If you wanted to correctly use GetSaved[1], the dictionary should be saved as an array when you’re saving:
    DS:SetAsync("id_"..plr.UserId, {table1})
  3. Tables do not have a value

I’d also suggest that you use BindToClose, because probably the server closes before it gets the chance to save the data:

game:BindToClose(function()
    for _,plr in pairs(game.Players:GetPlayers()) do
        DS:SetAsync("id_" .. plr.UserId, table1)
    end
end)
3 Likes

Understood. Thanks a lot man!

About the BindToClose, where would you need to put those lines of code?

Perhaps underneath the PlayerRemoving event:

game.Players.PlayerRemoving:Connect(function(plr)
	DS:SetAsync("id_"..plr.UserId, table1)
end)

-- BindToClose code here
1 Like

Ah thank you, I will try this out right now! Hopefully it works.

Is it normal to have this after adding the BindToClose?

Yes, it occurs because there is a limit to how many requests can be sent to the same key at a time: each request should have a 6-second cooldown inbetween.

Though, this isn’t really a problem, as the datastore request will eventually be handled and taken once the request queue has space, but if it’s filled then it will not handle the requests, but I don’t think it’ll happen

1 Like

It kinda works, there’s only one problem.

So to test it, I added two remote functions which change ‘table1.Adam’ accordingly. : image

(They are fired when a text button is clicked)
The problem is that whenever these remote functions are fired and ‘table1.Adam’ changes it works, but whenever you join and you don’t click on any buttons to change the ‘table1.Adam’, it returns back to “Sandler”.
Basically it doesn’t persist unless I change it.

Mind showing all of the code for the datastore?

1 Like

Here it is.
image

Also :
image

Is this supposed to be SetASync or GetASync?

It’s probably because it’s not saving at all, and the line you are questioning seems to reset it because GetSaved is nil. You could try putting a print under the GetSaved variable to see if it gives nil or not.

The line in question is supposed to save the data when the player doesn’t have any data saved in the datastore

But if GetSaved is nil how is it printing the 13th line?

It never prints nil btw. It prints a table but never nil.

It is also best to use UpdateAsync instead of setAsync to save UpdateAsync updates it and setAsync overwrites it so more chance on losing data.

1 Like

After reading through your post, I realized the issue:

If you’re in a game and don’t change the values at all, table1 will remain the same and the data will overwrite the saved data

1 Like

So what would I need to do please?

You can use UpdateAsync as @DevLevii said. You can check if the value is the default table with the function, if it isn’t you can update it.

DS:UpdateAsync(playerkey, function(oldValue) 
    if oldValue.Adam == "Sandler" then
       return table1
    else
       return nil -- cancels the update
    end
end) 

Or an alternative would be just to save the data when it changes (i. e: save the data in the RemoteFunctilon code)

1 Like

That will only work until you change the value once, since the value is no longer “Sandler” .
i.e if you change the value from “Sandler” it will keep returning nil after.

Oh hey, I managed to fix your code.

it should be :

DS:UpdateAsync(playerkey, function(oldValue) 
    if oldValue.Adam == oldValue.Adam then --if it's equal to the old value of Adam
       return table1
    else
       return oldValue -- Old table
    end
end)
1 Like

Shoot welp, it still doesn’t work.

The thing is, whenever the server starts the table will start as listed on the script