How to loop in a DataStore?

Hey! For my DataManager script, I added some code to convert the value: score so that it can be processed onto a leaderboard.

Section of script responsible for converting:
function ConvertScoreListToODS()
	for order, store in pairs(InfoStore) do
		local UserID = store.key
		local score = store.Score
		ScoreOrd:SetAsync(UserID,score)
	end
end

function LoopCSLTO()
	while true do
		task.wait(12)
		ConvertScoreListToODS()
	end
end
The entire DataManager script:
local RepStore = game:GetService("ReplicatedStorage")
local SvrStore = game:GetService("ServerStorage")
local DatStore = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local PlayerDataFolder = RepStore.PlayerData

local InfoStore = DatStore:GetDataStore("PlayerData")
local ScoreOrd = DatStore:GetOrderedDataStore("OrderedPlayerScore")

local Incall = game.ServerScriptService.DataManager.InCall

function UnloadPlayerData(PlayerID)
	local success, err = pcall(function()
		local PlayerData = InfoStore:GetAsync(PlayerID)

		if not PlayerData.Level and PlayerData.Score then
			warn("data empty")
			PlayerData = {}
			PlayerData.Level = 0
			PlayerData.Score = 0
		end

		local PlayerFolder = Instance.new("Folder")
		PlayerFolder.Name = PlayerID
		PlayerFolder.Parent = PlayerDataFolder

		for store, data in pairs(PlayerData) do
			local IntHolder = Instance.new("IntValue")
			IntHolder.Name = store
			IntHolder.Value = data
			IntHolder.Parent = PlayerFolder
		end
	end)
	if not success then warn(err) end
end

function PackPlayerData(PlayerID)
	local PlayerFolder = PlayerDataFolder:FindFirstChild(PlayerID)
	local success, err = pcall(function()
		local PlayerData = {}

		for i, v in pairs(PlayerFolder:GetChildren()) do
			PlayerData[v.Name] = v.Value
		end

		InfoStore:SetAsync(PlayerID,PlayerData)
	end)
	if success then
		PlayerFolder:Destroy()
	else
		warn(err)
	end
end

function TranslateCall(callData)
	for i, v in pairs(callData) do
		local suc, err = pcall(function()
			local PlrId = v.PlrId
			local Ttype = v.Type
			local value = v.Value
			local LPlrFol = PlayerDataFolder[PlrId]
			local SVal = LPlrFol[Ttype]
			SVal.Value = SVal.Value + value
		end)
		if not suc then warn(err) end
	end
end

function ConvertScoreListToODS()
	for order, store in pairs(InfoStore) do
		local UserID = store.key
		local score = store.Score
		ScoreOrd:SetAsync(UserID,score)
	end
end

function LoopCSLTO()
	while true do
		task.wait(12)
		ConvertScoreListToODS()
	end
end



LoopCSLTO()
Players.PlayerAdded:Connect(UnloadPlayerData)
Players.PlayerRemoving:Connect(PackPlayerData)
Incall.Event:Connect(TranslateCall)

Here is the error message:
image

You are attempting to iterate through a DataStore instance here;

function ConvertScoreListToODS()
	for order, store in pairs(InfoStore) do --> InfoStore
		local UserID = store.key
		local score = store.Score
		ScoreOrd:SetAsync(UserID,score)
	end
end

When you can only do this type of iteration with a table. I think a different way you can do this instead is by saving score data for people in the server every x amount of seconds and have it save to the Ordered Data Store.

function ConvertScoreListToODS()
	for order, plr in pairs(Players:GetPlayers()) do
		local PlayerData = InfoStore:GetAsync(plr.UserId)
		if PlayerData then
			local score = PlayerData.Score
			ScoreOrd:SetAsync(plr.UserId,score)
		end
	end
end

This I’d only recommend to do maybe every 30 seconds to 1 minute though, they could also leave in between these intervals and their data might not be saved to the ordered data store. I usually combat this by also attempting to save to the ODS when they leave as well. Be cautious with how frequent the DataStore tries to load or save data because it could cause players to lose data entirely.

1 Like

well, since my game hasn’t been released yet, I am storing the player score data to the score OrderedDataScore when the player leaves and the rest of their data is saved.

The function I provided should work then, considering there is no true way to get every datastore and all individual data; if it did it’d be really unhealthy for the server.

1 Like

by the way, for a pcall(), is there a way to get what line the errorMessage is referring to?

I’m pretty sure there isn’t. You can always look at whatever is inside of the pcall scope and figure out what line it is based off of the error message.

well, I am experiencing an issue here:

function UnloadPlayerData(PlayerID)
	local success, err = pcall(function()
		local PlayerData = InfoStore:GetAsync(PlayerID)

		if not PlayerData then
			warn("data empty")
			PlayerData = {}
			PlayerData.Level = 0
			PlayerData.Score = 0
		end
		
		if not PlayerData.Level or PlayerData.Score then
			PlayerData.Level = 0
			PlayerData.Score = 0
		end

		local PlayerFolder = Instance.new("Folder")
		PlayerFolder.Name = PlayerID
		PlayerFolder.Parent = PlayerDataFolder

		for store, data in pairs(PlayerData) do
			local IntHolder = Instance.new("IntValue")
			IntHolder.Name = store
			IntHolder.Value = data
			IntHolder.Parent = PlayerFolder
		end
	end)
	if not success then warn(err) end
end

Oh yeah, completely disregard what I said about that. The problem would be at line 29. ‘PlayerID’ must be the player instance instead of the actual userId because that’s the first paramater of PlayerRemoving. Try PlayerID.UserId instead.

function UnloadPlayerData(PlayerID)
    PlayerID = PlayerID.UserId
	local success, err = pcall(function()
		local PlayerData = InfoStore:GetAsync(PlayerID)

		if not PlayerData then
			warn("data empty")
			PlayerData = {}
			PlayerData.Level = 0
			PlayerData.Score = 0
		end
		
		if not PlayerData.Level or PlayerData.Score then
			PlayerData.Level = 0
			PlayerData.Score = 0
		end

		local PlayerFolder = Instance.new("Folder")
		PlayerFolder.Name = PlayerID
		PlayerFolder.Parent = PlayerDataFolder

		for store, data in pairs(PlayerData) do
			local IntHolder = Instance.new("IntValue")
			IntHolder.Name = store
			IntHolder.Value = data
			IntHolder.Parent = PlayerFolder
		end
	end)
	if not success then warn(err) end
end
1 Like

Thanks, I went through the code and spotted the same error.