How would I access ProfileService Data Tables

It is useless, because you’re wasting data by saving them as nested tables, instead of just the values themselves. You should only use tables when you need to use them, like saving owned cars and plots.

@Katrist it’s useless for the computer yes. Very handy for human readability though.

@LeCrabCurry You can do

return profile.Data["PlayerStats"]["Health"]

The two strings can be configurable parameters of your get function.

This is what comments are for though, it’s just added complexity having to comb through a table to find the data you really want to retrieve.

function PlrDataHandler:Set(player, key, value) -- key = {"PlayerStats", "Health"}

would making a path like this work? if so how would I incorporate this into my script to find the profile.Data[data1][data2][data3], etc

You would do something like this (index is a more suitable name):

function PlrDataHandler:Set(player, index, key, value)
	--[[
	Index = table name
	Key = value name
	Value = key's new value
	]]
	
	local profile = GetProfile(player)
	
	assert(profile.Data[index][key], string.format("Data does not exist for key %s", key))
	assert(type(profile.Data[index][key]) == type(value))
	
	profile.Data[index][key] = value
	
	local valueOBJ = player:FindFirstChild(key, true)
	
	if valueOBJ then
		valueOBJ.Value = value
	end
end

But what if I want to include more data? such as Inventory = {Item = {Stats = {"A","B","C"}}}
I was thinking of using some sort of loop, for example if the path was {“Inventory”, “Item”, “Stats”, “A”}, then I’d loop through it

function FindPath(path) --  path = {"Inventory", "Item", "Stats", "A"}

local currentPath = profile.Data
for i, v in pairs(path) do
currentPath = currentPath[path[i]]
end
return currentPath -- profile.Data[Inventory]["Item"]["Stats"]["A"]
end

Apologies for not formatting since its just a mockup code I wrote right now, but in theory would this work?

Actually, you can get values nested in tables. You’d have do a deep search, which is possible by modifying the deep clone code in the docs, which I have done here:

local Data = {
	["PlayerStats"] = {
		["Chakra"] = 0,
		["Strength"] = 0,
		["Health"] = 0,
	},
	["Levels"] = {
		["Level"] = 1,
		["Exp"] = 0,
		["Points"] = 0,
	}
}

local function setValue(tbl, key, value)
	for k, v in pairs(tbl) do
		if type(v) == "table" then
			v = setValue(v, key, value)
		end
		
		if k == key then
			tbl[k] = value
		end
	end
end

setValue(Data, "Points", 5) -- Sets the value of Points to 5

This should work, do a test with a print statement after setting a value and see if it updated.

Never said it wasn’t possible. I’m saying that it’s highly impractical to do so, because you’re wasting time combing through tables to reach just 1 value.

Would thus work?
function FindPath(path) – path = {“Inventory”, “Item”, “Stats”, “A”}

local currentPath = profile.Data
for i, v in pairs(path) do
currentPath = currentPath[path[i]]
end
return currentPath -- profile.Data[Inventory]["Item"]["Stats"]["A"]
end

You’re only returning the value in that function, so you wouldn’t be able to mutate that value after. You’re close though.

hm I see, so then what should I do? use table.concat? or would that not apply here

You can just set the value in that function. You could also use a recursive search like @ltsmrsky did.

You said his method is impractical, why is that? Will it take a lot of memory?

I had the same issue but I fixed it by creating a function that lets you access tables like you can access the workspace (PlayerStats.Weapons.Weapon):

GetData({"PlayerStats", "Weapons", "Weapon"}) --// Returns DatastoreProfile.PlayerStats.Weapons.Weapon

If you get what I mean. I’m not home right now so I can’t reply with a script.

Edit:

function SearchTable(Table, directory)
	local Int = 0;
	while Int < #directory do
		Table = Table[directory[Int + 1]];
		Int += 1;
	end;

	return Table;
end;

function RetrieveData(Player, directory)
	local ReturnData = SearchTable(Profiles[Player].Data, directory);

	if ReturnData ~= nil then
		return ReturnData;
	else
		warn("Data not found.");
		return nil;
	end;
end;
1 Like

Yes, it takes a lot more memory and a lot more time to search for the data.

This is similar to the mockup I made, but also wouldn’t the function just return the value of the index we are trying to search for?

Nope, it returns an editable index.

Example:

local Players = game:GetService("Players");
local Client: Player = Players[Player];
local ClientData = DataManager:RetrieveData(Client, {"Data", "PlayerStats"});
	
ClientData.Chakra += 1;
ClientData.Strength += 1;
ClientData.Health += 10;

I’ve used your function, but now I’m getting an error.
ServerScriptService.DataHandler:113: profile does not exist for 2231850740

function GetProfile(plr)
	assert(profiles[plr], string.format("profile does not exist for %s", plr.UserId))
	return(profiles[plr])
end

Also when I print profiles it returns an empty table. Though I’m not sure if this is because of the table combing system I added or it’s something else…

On the scale you’re working at you won’t notice any difference.

Minute (useless) optimizations should be more important than code readability.

It’s not impractical at all.

1 Like

What do you mean by “table combining system”, could you elaborate?

And has this error occured before?