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

It’s not possible to do outside of in game itself, as there’s no way to get a list of every data store.

What you can do is, if a player does not have data in the standard data store, check the ordered backups store instead, and move their data over at that point.

1 Like

I have no idea what you’re talking about, none of this is related to DataStore2.

How would you get an updated dictionary? I tried looking into :GetTable() but I’m still getting nil for recently added values.

local DataStore2 = require(1936396537)
local MainKey = "MainKey"
DataStore2.Combine(MainKey, "Statistics", "Profile", "Character", "Equipment", "Inventory")

local function SetDataTable()
	local UserData = {
		Statistics = {
			["Level"] = 0;
			["XP"] = 0;
		};
		
		Profile = {
			["Title"] = "Default"
		};
		
		Character = {
			["Face"] = "Skeptical";
		};
		
		Equipment = {
			["Tool 1"] = "Cola";
			["Tool 2"] = "Chocolate";
		};
		
		Inventory = {
			["Item 1"] = true;
			["Item 2"] = false;
            ["Item 3"] = false; -- Recently added
		}
	}
	return UserData
end

As you can see for Item 3 under Inventory, there is a comment that says “Recently added”, which indicates that I implemented it in a later update for a game. With that being said, whenever I make new code using Item 3, I would get a nil value. I’ve tried using :GetTable() and other methods I’ve found through DevForums such as this but I still have no luck.

game.Players.PlayerAdded:Connect(function(player)
	local UserData = DataStore2(MainKey, player):Get(SetDataTable())
	
	local StatisticsData = DataStore2("Statistics", player)
	local ProfileData = DataStore2("Profile", player)
	local CharacterData = DataStore2("Character", player)
	local EquipmentData = DataStore2("Equipment", player)
	local InventoryData = DataStore2("Inventory", player)
end)

ReplicatedStorage.Functions.GetContent.OnServerInvoke = function(plr, Type)
		if player.Name == plr.Name then
			if Type == "Level" then
				return StatisticsData:Get(UserData.Statistics).Level
			elseif Type == "XP" then
				return StatisticsData:Get(UserData.Statistics).XP
			elseif Type == "Credit" then -- Recently added
				return StatisticsData:Get(UserData.Statistics).Credit
			end
		end
	end

For additional information in regards to my problem, this is a sample code that compiles correctly. However, if I were to implement “Credit” under Statistics from the Dictionary function, I would get nil.

Are there any particular ways you have in mind in getting an updated dictionary? Thanks.

1 Like

Don’t do this. This is an outdated model and the documentation tells you the correct way to get this.

Don’t do this either. The documentation explicitly tells you not to.

You should not get nil if you use stores as proper individual pieces of data, and use :Get(defaultValue) correctly.

1 Like

How would I remove a players data from the game. I look through the documentation and I cannot seem to find it.

This has been answered tens of times before, please search for it.

i got a question, can I change Value into StringValue, cuz I had the client ready to fire, coming from TextBox.Text into pointstore:Set(TextBox.Text). It does work but, it’s alway blank or doesn’t say anything, I try everything I could, is there anyway?

game.ReplicatedStorage.Rename.OnServerEvent:Connect(function()
	
local pointsStore = DataStore2("Rename", player)

--local BotName = player.PlayerGui.ScreenGui.RenameF.Frame.TextBox.Text
local BotName = player.PlayerGui:WaitForChild("ScreenGui").RenameF.Frame.TextBox:FindFirstChild("Name")
game.ReplicatedStorage.Player[player.Name].Rename.Value = BotName.Value	
	print(game.ReplicatedStorage.Player[player.Name].Rename.Value)
pointsStore:Set(game.ReplicatedStorage.Player[player.Name].Rename.Value)		
	
end)

You can’t access GUI values from the server. They are only on the client. Use RemoteEvents.

DataStore2 appears to only work with player instances. I’m going to have to rewrite this to work with keys that aren’t player or Instance based.

Hi,
i am trying to implement soft shutdown script. But because of Datastore 2 setting player parent to nil i am unable to teleport player to Reserved Server.
My solution is replacing player.Parent = nil to firing local function

Here is modified code:

local isx = true --Variable making sure function runs only once
	
	local function SaveOnLeave()
		if isx == true then
			if player:IsDescendantOf(game) then return end
			isx = false
			--playerLeavingConnection:Disconnect()
			--wait(0.65)
			dataStore:SaveAsync():andThen(function()
				--			print(tick())
				print("player left, saved " .. dataStoreName)
			end):catch(function(error)
				-- TODO: Something more elegant
				warn("error when player left! " .. error)
			end):finally(function()
				event:Fire()
				fired = true
			end)
			--print("saved1")
			delay(40, function() --Give a long delay for people who haven't figured out the cache :^(
				DataStoreCache[player] = nil
			end)
		end
	end
	
	
	game:BindToClose(function()
		if not fired then
			spawn(function()
				SaveOnLeave()
				--player.Parent = nil -- Forces AncestryChanged to fire and save the data
			end)

			event.Event:wait()
		end

		local value = dataStore:Get(nil, true)

		for _, bindToClose in pairs(dataStore.bindToClose) do
			bindToClose(player, value)
		end
	end)
		
	
	playerLeavingConnection = player.AncestryChanged:Connect(function()
		SaveOnLeave()
	end)

I only tested it on small scale and seemed to work fine.
But i want to ask could this cause any problems?

The latest version should have fixed this, we no longer parent player to nil.

2 Likes

I’ve been doing some scripting for a friend’s game and am using datastore2 for the saving.
I think I understand most of the basics but I was unsure about where I can place what code.
Do I just have to have the combine method in one of my server scripts?
Am I able to use the Get, Set, Save, and Increment methods in separate scripts from where combine is done?
So if I have a server script with just the combine and had scripts in different objects that run Increment separately, for example on a touch event, without combining within those scripts?
Would it be better if I used bindables to do all of the Get, Set, Save, and Increment in the same script as combine? Or would it be worse?
What kind of problems do each of the ways cause, if any?

Also, should I be running the Save method every time someone buys an item or currency? Would that cause clogging?

Please tell me if I seem to be misunderstanding something.
I’m using one of the most recent versions.

Yes, as long as you ensure the Combine runs before any of those methods are called.

Just use a ModuleScript if you’re so concerned.

If “buy” means with Robux, then yes, I think so, but be cautious as, especially without Standard saving, you could cause issues.

Thanks,
Wouldn’t a ModuleScript do the same thing in the same place though? Just partly being written in a separate script?
Yes, with Robux. What does Standard saving mean?

There’s just no real reason to have a BindableEvent when only one thing is connected to it, and with deferred signals coming up, you won’t know for sure that its combined by then.

https://kampfkarren.github.io/Roblox/advanced/saving_methods/

Hello, I tried to decrease a NumberValue using :Increment() but It doesn’t work

Like this:

local DataStore2Module = game.ReplicatedStorage.DataStore2Module

DataStore2Module.Combine("Leaderstats", "Coins")

game.Players.PlayerAdded:Connect(function(Player)
      local CoinStore = DataStore2Module("Coins")

      local leaderstats = Instances.new("Folder", Player)
      leaderstats.Name = "leaderstats"

      local Coins = Instances.new("NumberValue", Player)
      Coins.Name = "Coins"

      Coins.Value = CoinStore:Get()

      ---Giving player a free coin
      CoinStore:Increment(50, 0)
      Coins.Value = CoinStore:Get()

      ---Decreasing players coin
      CoinStore:Increment(0, 0)    --- Doesn't work
      Coins.Value = CoinStore:Get()
end)

Doesn’t increment add? I think it is working but it isn’t doing anything because you’re not adding or subtracting anything.

Why didn’t I think of this

			BitsStore:Increment(-Bits.Value, 0)
			Bits.Value = BitsStore:Get()

So I want to make a leader board and i dont know how to store a value like

   local leaders = {
   ["first"] = ["hellothere3681", 1.7682]
   ["second"] = ["goodbyethere", 2.6880]
}

how would i do this?
also how would i get this value

I’m having an issue with my upgrades script, I’m not sure if its me or DataStore2.

Here is the localscript which fires a remoteEvent to start a server script function.

ClickingDeviceUpgrade.OnServerEvent:Connect(function(player)
	
	local circleStore = DataStore2("circles", player)
	local deviceUpgradeStore = DataStore2("deviceUpgrade", player)
	
	local bought = false
	local cost = 10000
	
	if player.leaderstats.Circles.Value >= cost then
		
		circleStore:Increment(-cost, 0)
		deviceUpgradeStore:Increment(1)
		bought = true
		ClickingDeviceUpdate:FireClient(player, bought)
	else
		bought = false
		ClickingDeviceUpdate:FireClient(player, bought)
	end
	
end)

Then my main script which handles the upgrade itself is here:

ClickingDeviceUpgrade.OnServerEvent:Connect(function(player)
	
	local circleStore = DataStore2("circles", player)
	local deviceUpgradeStore = DataStore2("deviceUpgrade", player)
	
	local bought = false
	local cost = 10000
	
	if player.leaderstats.Circles.Value >= cost then
		
		circleStore:Increment(-cost, 0)
		deviceUpgradeStore:Increment(1)
		bought = true
		ClickingDeviceUpdate:FireClient(player, bought)
	else
		bought = false
		ClickingDeviceUpdate:FireClient(player, bought)
	end
	
end)

What is my issue?