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

File an issue on GitHub after making sure you are on the latest release, I have not heard of this behavior.

1 Like

I was reading your API… is it now recommended to use SaveAsync() instead of Set() ?

1 Like

What? They do completely different things, I’d suggest reading the example again.

1 Like

How i can use DataStore2 without a player.
For example load a house or smth like this.

1 Like

I am just confused, I am combining 10 different keys to “DATA” I am storing different values like int, table and bool. I am using :Get() on all of them and it doesnt actually work it just simulates storing, but there is no saved data upon rejoining, it only works if there is only one key.
I discovered this in gotchas page:

  • Because of the throttles on OrderedDataStores, DataStore2 (with the default saving method) is only guaranteed to not throttle on :Get() if you use less than 2 unique keys.

I assume my data is broken of that reason, which method should I use instead of Get() ? I also dont want to be forced to set defoult value as a parameter if possible

1 Like

You can’t. Datastore2 is attached to the player instance. If you want to do datastores for house, etc I recommend ProfileService by @loleris

2 Likes

If they’re all combined under one DATA key, then this limitation does not apply to you. If they’re not, then you are not using the module correctly.

1 Like

I need help with understanding :OnUpdate()
So I wrote some code to test ds2 and I am confused with what I got,

local datastore2 = require(script.Parent:WaitForChild("DataStore2"))
datastore2.Combine("DATA", "money", "codes")

game.Players.PlayerAdded:Connect(function(plr)
	local money = datastore2("money", plr)
	money:OnUpdate(print(money:Get()))
	money:Set(money:Get(0) + 1)
	--------------------------------
	local codes = datastore2("codes", plr)
	codes:OnUpdate(print(table.unpack(codes:GetTable({}))))
	local new = codes:GetTable({})
	print(#new)
	new[#new + 1] = "n"
	codes:Set(new)
end)

Its confusing because it actually prints this:
image
which means that OnUpdate was ran before print(#new), eventhough the line where I am changing datastore is a few lines below!

2 Likes

OnUpdate takes a function. You are not passing a function.

money:OnUpdate(function()
    print(money:Get())
end)
2 Likes

It is erroring…

local DefaultValue = {
	Gears = {0};
	Cosmetics = {0};
}

local DatastoreName = "Datastore"

local PlayerData = {}

local DataStore2 = require(script.Parent:WaitForChild("DataStore2"))

game.Players.PlayerAdded:Connect(function(Player)
	local Storage = DataStore2(DatastoreName, Player)
	PlayerData[Player.UserId] = Storage:Get() or DefaultValue -- this loads the data
	
	while true do
		wait(200)
		Storage:Set(PlayerData[Player.UserId])
	end
end)


game.Players.PlayerRemoving:Connect(function(Player)
	local Storage = DataStore2(DatastoreName, Player)
	Storage:Set(PlayerData[Player.UserId]) -- this saves the data
end)

game:BindToClose(function()
	for _, Player in pairs(game.Players:GetPlayers()) do
		local Storage = DataStore2(DatastoreName, Player)
		Storage:Set(PlayerData[Player.UserId]) -- this saves the data
	end
end)

“error when player left! Invalid at input.Cosmetics because: Mixed Array/Dictionary”

Not sure what I have done wrong and how I can fix it. Help is definitely appreciated!!

1 Like

I recommend reading your error.

This is completely pointless. You should be calling :Set every time the data changes instead of just every 200 seconds. You are treating DataStore2 the same way you would normal data stores, which you should not.

game:BindToClose(function()
	for _, Player in pairs(game.Players:GetPlayers()) do
		local Storage = DataStore2(DatastoreName, Player)
		Storage:Set(PlayerData[Player.UserId]) -- this saves the data
	end
end)

Same with this. This makes absolutely no sense, :Set doesn’t save the data.

I recommend reading the documentation for DataStore2.

1 Like

How to use datastore2.combine?

2 Likes

You need to read the “Documentation” section where it has explanations for its API

datastore2.Combine("MainKey","coins","levels","XP", etc.. )

Have a good day

3 Likes

Hi! My problem is that data is just not saving eventhough OnUpdate fires and when I print the data inside it prints as expectedly. Also every other key I change with that purchase like money, gets updated but not saved upon rejoining. Please help! (not testing in studio)

local datastore2 = require(script.Parent:WaitForChild("DataStore2"))
datastore2.Combine("DATA", "money", "weapon")

local weapons = {
	["CandyCane"] = {10000000000, false},  -- PRICE, OWNED
	["DoubleRevolver"] = {1230, false},
	["DoubleRifle"] = {5280, false},
	["GoldenRevolver"] = {590, false},
	["Minigun"] = {1000000000000, false},
	["SingleRifle"] = {1850, false},	
	["GoldenRifle"] = {2660, false}
}

coroutine.wrap(function() -- new thread so I can run this and OnUpdate()
	someInvoke.OnServerInvoke = function(plr, gun)  -- invoke when buying guns, gun - gun.Name
		local weaponStore = datastore2("weapon", plr)
		datastore2("money", plr):Increment(-price, 0)
		weaponStore[gun][2] = true 
		datastore2("weapon", plr):Set(weaponStore)  -- seting owned to true
		game:GetService("ServerStorage").Weapons[gun]:Clone().Parent = plr.Character
		print("done") -- it prints done
		return 1
	end	
end)() 	

game:GetService("Players").PlayerAdded:Connect(function(plr)
	local weaponStore = datastore2("weapon", plr)
	print(table.unpack(weaponStore:GetTable(weapons)["GoldenRevolver"])) -- always prints 590, false
	weaponStore:OnUpdate(function()
		print(weaponStore:GetTable(weapons)["GoldenRevolver"][2]) -- after I do Set() it prints true
	end)
end)
1 Like

I’m still confused with this script line. What’s the target of the require? Is it the MainModule or something?

local DataStore2 = require(ServerScriptService.DataStore2)
2 Likes

yeah its the mainmodule of the datastore2

3 Likes

Is it possible to save player’s backpack using DataStore2. If yes, how?

2 Likes

Its actually simple.

You need to have a few thimgs set-up first,

A folder which will store all the tools/instances.

A table in your script as example follows:

Local tools = {
  ["Sword"] = REFERENCE_TO_YOUR_TOOL_FROM_THE_FOLDER

--Etc
}

Then using datastore2 make a store which saves the backpack as a table, ex {sword,axe}

If you want to add a tool or any instance to the player’s backpack. You don’t actually parent it to the players backpack but add the name to the table and listen for OnUpdate and find the added instance from the added name from the tools table, in this case, and parent it to the players backpack.

When the player joins loop through the table and find the name from folder and parent it to the players backpack.

2 Likes

I was reading a bit more into :SetBackup() and I’m not sure which approach is valid to check whether a datastore is using a backup version.

This function below is the first thing that is run when a player joins the game.
Do I have to call :Get() before checking whether the datastore is a backup?

PlayerDataDatastores.CheckForIsBackup = function(player)
	local PlayerDataDataStore = DataStore2("PlayerData", player)
	PlayerDataDataStore:SetBackup(5)

    --is it necessary to use :Get() / :GetTable() before using the IsBackup()?

	if PlayerDataDataStore:IsBackup() then
		player:Kick("There was an error with loading your data. Please rejoin the game!")
		return "isBackup"
	end
	return PlayerDataDataStore
end

The documentation shows the following:

local coinsStore = DataStore2("coins", player)
coinsStore:SetBackup(5)
print(coinsStore:IsBackup()) -- will print "true" if DataStore2 couldn't successfully get the data
1 Like

Yes, because otherwise there’s no time for it to actually try to retrieve the data.

2 Likes