Datastore Loss Data Help

Hello, I’m new to the forums so sorry if this is the wrong category or something.

I had an issue with my game saving data, I had some reports by players getting their data loss. Below is my script to save player’s data. Now, I’m asking how can I improve the way I save my players data to ensure data loss will never happen again?

local DataStoreService = game:GetService(“DataStoreService”)
local DataStore = DataStoreService:GetDataStore(“Cash”)
local DataStore1 = DataStoreService:GetDataStore(“Wins”)
local DataStore2 = DataStoreService:GetDataStore(“Donated”)
local DataStore3 = DataStoreService:GetDataStore(“EasyWins”)
local DataStore666 = DataStoreService:GetDataStore(“ImpWins”)
local trail1 = DataStoreService:GetDataStore(“trailcyan”)
local trail2 = DataStoreService:GetDataStore(“trailpurple”)
local LeveLStore = DataStoreService:GetDataStore(“LeveL”)
local levelleaderboard = DataStoreService:GetDataStore(“LeveLboard”)
local secsStore = DataStoreService:GetDataStore(“Time Played”)
local earnedCoinsStore = DataStoreService:GetDataStore(“Earned”)
local spentCoinsStore = DataStoreService:GetDataStore(“Spent”)
game.Players.PlayerAdded:Connect(function(Player)

local Leaderstats = Instance.new("Folder")
Leaderstats.Name = "leaderstats"
Leaderstats.Parent = Player

local LeveL = Instance.new("NumberValue")
LeveL.Parent = Leaderstats
LeveL.Name = "LeveL"
LeveL.Value = 0

local Leaderstats2 = Instance.new("Folder")
Leaderstats2.Name = "leaderstats2"
Leaderstats2.Parent = Player

local Currency = Instance.new("IntValue")
Currency.Parent = Leaderstats2
Currency.Name = "Cash" 
Currency.Value = 0

local Donated = Instance.new("IntValue")
Donated.Parent = Leaderstats2
Donated.Name = "Donated"
Donated.Value = 0

local wins = Instance.new("IntValue")
wins.Parent = Leaderstats2
wins.Name = "Wins"
wins.Value = 0

local easywins = Instance.new("IntValue")
easywins.Parent = Leaderstats2
easywins.Name = "EasyWins"
easywins.Value = 0

local ImpWins = Instance.new("IntValue")
ImpWins.Parent = Leaderstats2
ImpWins.Name = "ImpWins"
ImpWins.Value = 0

local trailcyan = Instance.new("IntValue")
trailcyan.Parent = Leaderstats2
trailcyan.Name = "trailcyan"
trailcyan.Value = 0

local trailpurple = Instance.new("IntValue")
trailpurple.Parent = Leaderstats2
trailpurple.Name = "trailpurple"
trailpurple.Value = 0

local check = Instance.new("IntValue")
check.Parent = Leaderstats2
check.Name = "check"
check.Value = 0

local LeveLboard = Instance.new("IntValue")
LeveLboard.Parent = Leaderstats2
LeveLboard.Name = "LeveLboard"
LeveLboard.Value = 0

local secs = Instance.new("IntValue")
secs.Parent = Leaderstats2
secs.Name = "Time Played"
secs.Value = 0	

local Earned = Instance.new("IntValue")
Earned.Parent = Leaderstats2
Earned.Name = "Earned"
Earned.Value = 0

local Spent = Instance.new("IntValue")
Spent.Parent = Leaderstats2
Spent.Name = "Spent"
Spent.Value = 0

local Data = DataStore:GetAsync(Player.UserId)
local Data1 = DataStore1:GetAsync(Player.UserId)
local Data2 = DataStore2:GetAsync(Player.UserId)
local Data3 = DataStore3:GetAsync(Player.UserId)
local Data666 = DataStore666:GetAsync(Player.UserId)
local datatrail1 = trail1:GetAsync(Player.UserId)
local datatrail2 = trail2:GetAsync(Player.UserId)	
local dataLeveLStore = LeveLStore:GetAsync(Player.UserId)
local dataLeveLboard = levelleaderboard:GetAsync(Player.UserId)
local datasecs = secsStore:GetAsync(Player.UserId)	
local dataEarned = earnedCoinsStore:GetAsync(Player.UserId)
local dataSpent = spentCoinsStore:GetAsync(Player.UserId)

if Data then
	Currency.Value = Data
	
end

if Data1 then
	wins.Value = Data1

end

if Data2 then
	Donated.Value = Data2
end

if Data3 then
	easywins.Value = Data3
	
end

	
if Data666 then
	ImpWins.Value = Data666

end	

if datatrail1 then
	trailcyan.Value = datatrail1
end
if datatrail2 then
	trailpurple.Value = datatrail2
end

if dataLeveLStore then
	LeveL.Value = dataLeveLStore
end
if dataLeveLboard then
	LeveLboard.Value = dataLeveLboard
end

if datasecs then 
	secs.Value = datasecs
end


if dataEarned then
	Earned.Value = dataEarned
end
if dataSpent then
	Spent.Value = dataSpent
end

end)

game.Players.PlayerRemoving:Connect(function(Player)
DataStore:SetAsync(Player.UserId, Player.leaderstats2.Cash.Value)
DataStore1:SetAsync(Player.UserId, Player.leaderstats2.Wins.Value)
DataStore2:SetAsync(Player.UserId, Player.leaderstats2.Donated.Value)
DataStore3:SetAsync(Player.UserId, Player.leaderstats2.EasyWins.Value)
DataStore666:SetAsync(Player.UserId, Player.leaderstats2.ImpWins.Value)
trail1:SetAsync(Player.UserId, Player.leaderstats2.trailcyan.Value)
trail2:SetAsync(Player.UserId, Player.leaderstats2.trailpurple.Value)
LeveLStore:SetAsync(Player.UserId, Player.leaderstats.LeveL.Value)
levelleaderboard:SetAsync(Player.UserId, Player.leaderstats2.LeveLboard.Value)
secsStore:SetAsync(Player.UserId, Player.leaderstats2[“Time Played”].Value)
earnedCoinsStore:SetAsync(Player.UserId, Player.leaderstats2.Earned.Value)
spentCoinsStore:SetAsync(Player.UserId, Player.leaderstats2.Spent.Value)
end)

3 Likes

hello what does your reply means? is my post illegal?

1 Like

It is completely unnecessary to have so many datastores (one for each stat), you only need one datastore to save the player’s data. To do this, store all of the stats in a single table and save that table to the datastore.

For example:

local data = {}
for _, stat in pairs(player.leaderstats:GetChildren())do
	data[stat.Name] = stat.Value
end
2 Likes

Yes thankyou for pointing this out, ill try this one. But will this prevent dataloss?

Most likely since you will only be changing or getting data from one datastore instead of 13 (at the same time).

2 Likes

I want to make sure if my understanding to your suggestion is correct. Are you referring to my “if data then”? so instead of writing many if for different stat, ill use for loop and a table right?

I think you have so many datastores that it’s queuing and preventing you from saving and getting data properly hence why you’re experiencing data loss.

Correct.

I should point out that if you now condense those 13 datastores into a single one, all of your players data would be wiped. Either you have to live with that or maybe run a transition period for week or two where if a player joins and they have data stored in the old datastores it grabs all the data from it, saves it in the new one and removes their data from the all the old datastores.

Note: Doing this transition period comes with the same risks of data loss, like as @RatiusRat said it would be querying the datastores to many times.

1 Like

How can I fix it? is the fix same with @adamaniac suggestion?

Just combine all data into 1 table so you only have to setasync once or getasync once.

3 Likes

No you do not need remotes at all. You can use modules that are required serversided.

1 Like

As others have said above, I recommend condensing all of the values into a table to require less writing to stores.

I also recommend using UpdateAsync() over SetAsync() because you can consider the old data values for data loss traits before writing.

Do NOT do this, data management should never touch the client or exploiters can modify data to their hearts’ content.

1 Like

Ok then. I get it. I wont use remotes. Check my title. Yes, it says Animator not Programmer.

The game has been running for months now so the data must be move to the new datastore but I have no idea on how I will grab the data from old datastore to save to new datastore, do you have any example so I can try to understand?

The issue with my game is that some of player’s data resets so by using UpdateAsync, will it prevent from getting the player’s data back to 0 instead it will only go back to the last saved data? for example, the player has 5 coins, but during the game it gets to 10 coins then he leaves the game or crashed the game. When he go back he will get 5 coins instead having 0 again? sorry for my bad english

Okay, essentially keep those datastores declared so they can be accessed, when a player joins create an empty table and run GetAsync on each datastore, if there is data for the player in those datastores, put the retrieved value in the table. Once that is done save that table to the new datastore and run RemoveAsync on each of those 13 datastores so it does not repeat this process again.

I suggest using some wait statements when getting and removing the data during the above process so that you do not reach the datastore limits quickly. It will slow the process but reduce the likelihood of failure.

1 Like

You can decide whether or not data gets forgotten with UpdateAsync(). I recommend reading this:

So you can either use the oldData parameter or you can forget about it, but UpdateAsync() has its uses either way.

2 Likes

Hello I still don’t understand well how to do what you suggested but I try this one which I feel I had many mistakes.

On top of the codes below the declaration of old datastore, I wrote this one

local player = game:GetService(“Players”)
local NewData = DataStoreService:GetDataStore(“NewData”)
–created empty table, im not sure if this should be global or inside the player added function
local data = {}

Inside the game players added function, I didn’t touch anything instead I just added this at the end of the function

if dataSpent then
	Spent.Value = dataSpent
end

--this one
for _, stat in pairs(player.leaderstats:GetChildren())do
	data[stat.Name] = stat.Value
end end)

Then on game players removing, I still didn’t touch anything but added this which I don’t know if correct

earnedCoinsStore:SetAsync(Player.UserId, Player.leaderstats2.Earned.Value)
spentCoinsStore:SetAsync(Player.UserId, Player.leaderstats2.Spent.Value)

--this one	
for _, stat in pairs(player.leaderstats:GetChildren())do
	NewData:SetAsync(Player.UserId,data[stat.Name].Value)
end	end)

On the RemoveAsync, I have no idea how I will write it on my codes.

I also want to ask before anything else, does saving the stats in a table can be accessed and used in ordered datastore? I have global leaderboard.

No, at least I don’t think it can. " A OrderedDataStore is essentially a GlobalDataStore with the exception that stored values must be positive integers ."