Folder:GetChildren() DataSave?

Is there a way to collect the children in a Folder and save the values to the DataStore using :GetChildren() or some other method that will collect the values and save them?

I have a folder that is empty, players collect items and the items are sent to that folder. I want to save what the user has collected.

2 Likes

You will need to do the get and save requests where shown, but this should help convert your folders into a saleable and load able format.

Be sure to define playerFolder

Saving:

--Saving data
local dataToSave = {}

for i,v in pairs(playerFolder:GetChildren()) do
     table.insert(dataToSave, v.Name)
end

--Save the table to a key
dataStore:UpdateAsync(key, function(oldValue)
    --Do some kind of check if you want
    return dataToSave
end)

Loading:

local loadedData = --Load data from key
local loadedData = dataStore:GetAsync(key) --Example
for i,v in pairs(loadedData) do
      local n = Instance.new('Folder')
       n.Name = v 
       n.Parent = playerFolder
end
3 Likes

Alternative


Instead of saving the whole instances, I recommend saving them through serialization or identifications of each item. Maybe even through the objects’ name.

After loading, or DataStore:GetAsync(), a table is returned from the data store which contains the items’ IDs, follows up by reading off the IDs but also important data with the object. The game will create the objects using the data read from the matching data.

To clarify exactly what do you do with the strings or numbers inside the table, you’ll need another table which is a structure containing the key which matches the contents of the table. Run a for loop throughout the table, and use the value to read the table’s key’s values.

-- table storing the key to respective contents
local coolTable = {
    [1] = {"cool contents bro"};
    [2] = {"cooler contents bro"};
    [3] = {"epic contents bro"}
}

-- load data
local success, data = pcall(DataStore.GetAsync, DataStore, key) -- key is associated key to the player
if success then
    for _, value in next, data["contents bro"] do
        print(value, coolTable[value]) -- if the value was 1, it would print out "cool contents bro"
    end
end

Otherwise, you can try the solution above.

1 Like

Did you mean to put SetAsync there? UpdateAsync doesn’t accept a table for its second field. You will also want to wrap GetAsync in a pcall.

How would I save the value of a NumberValue?

I made a tutorial which will help you with your use case last year.

1 Like

Fixed my reply to work with updateAsync, I don’t know what I was thinking. UpdateAsync uses a function not a value.

Made this yesterday. It’s pretty cool.

Saving

local key =  -- Set your Key
local datastore =  game:GetService("DataStoreService"):GetDataStore("") -- DataStore Name
local datatable = {}
local tablenum = 0
local folder = -- Folder
for _,value in pairs(folder:GetChildren()) do --Only Values can be in the Folder
	tablenum = tablenum + 1
	table.insert(datatable,tablenum,{["Value"] = value.Value;["Name"] = value.Name})
end
local success, err = pcall(function()
	datastore:UpdateAsync(key, function(old) -- Updates Data
		local new = old or nil
		new = datatable
		return new
	end)
end)

Loading

--Create Values
local datastore =  game:GetService("DataStoreService"):GetDataStore("") -- DataStore Name
local datatable = datastore:GetAsync(player.userId)
if datatable then
	local folder = -- Folder
	local tablenum = 0
	for _,value in pairs(folder:GetChildren()) do --Only Values can be in the Folder
		local data = nil
		for i = 1, #datatable do
			local check = datatable[i]
			local name = check["Name"]
			if name and value.Name == name then
				data = check
			end
		end
		if data ~= nil then
			if value.Name == data.Name then
				value.Value = data.Value
			end
		end
	end
end
2 Likes

There’s no reason to use UpdateAsync over SetAsync if you’re not checking the old values. You’re just overcomplicating your script in this case.

UpdateAsync is always better practice, and setAsync overrides the value directly. I wanted to make sure the @OP knew that there was a ability to do so; I didn’t want them to lose data later on because they didn’t know about it. That’s why I added that you could do a check if you wanted.

UpdateAsync is only a better practice because it gives you the old value. The function itself is not inherently better to use. If you don’t use the old value, it’s just as bad, if not worse, since you’re creating a pointless function that just returns one value.

Saying “Do some kind of check if you want” can be a bit misleading, since there’s no reason to use UpdateAsync it you aren’t doing any kind of checks.

There’s a point on the other thread about the inherent benefits of UpdateAsync that are skipped over, primarily the operations done on the backend, the workflow of Get-Set-Update and caching.

UpdateAsync isn’t pointless, even if you throw away the oldValue (which really you shouldn’t).

I actually use this same method. After my DataService loads a player’s data from the datastores and validates it, it converts the data table containing the player’s data (mind you the table has many sub-tables as well) into a folder/value structure, and places it in ReplicatedStorage.
When the data is saved, I simply convert the data from its folder/value structure back into a table structure.

I do this so Roblox replication can handle the replication of any changes to my player’s data, mainly because I’m too lazy to write my own replication system to replicate data changes to the client.

I have two useful functions in my table util module called ConvertTableToFolder and ConvertFolderToTable that allow me to do this. Please keep in mind that the code is old, so it’s a bit ugly.

ConvertFolderToTable.lua:

local function ConvertFolderToTable(Folder)
	local Tab={}
	local Keyname;
	local Value;

	for i,v in pairs(Folder:GetChildren()) do
		if v:IsA("Folder") then
			Value=ConvertFolderToTable(v)
			Keyname=v.Name
		else
			Keyname=v.Name
			Value=v.Value
		end
		Tab[Keyname]=Value
	end
	return Tab
end

return ConvertFolderToTable

ConvertTableToFolder.lua:

local function ConvertTableToFolder(Original_Table)
    local Folder=Instance.new('Folder')
	local Object;

    for Index,Value in pairs(Original_Table) do
        if typeof(Value)=="table" then
            Object=ConvertTableToFolder(Value)
        else
            if typeof(Value)=="number" then
                Object=Instance.new('NumberValue')
            end
            if typeof(Value)=="string" then
                Object=Instance.new('StringValue')
            end
            if typeof(Value)=="boolean" then
                Object=Instance.new('BoolValue')
            end
            if typeof(Value)=="Instance" then
                Object=Instance.new('ObjectValue')
            end
            Object.Value=Value
        end
        Object.Name=Index
        Object.Parent=Folder
    end
    return Folder
end

return ConvertTableToFolder

Thanks for the outline! Changed up some stuff until I was satisfied with the outcome.

1 Like

Solution

Nearly all of these were great and work. Pick and choose the one you want to use!

How do you set the key? I tried, but it was an error.