How would I be able to combine 6 DataStores in 1 DataStore?

Hello developers! I am in need of some help rn. Someone suggest one day on a different topic to use 1 DataStore for everything. However, I just don’t know how to combine these into one.
image
CreateFolder.lua is the one that creates the folder.

Here is an example script:

local DataStore = game:GetService("DataStoreService")
local ds = DataStore:GetDataStore("SpaceHighway")

game.Players.PlayerAdded:Connect(function(player)
	local leader = player:WaitForChild("TimeTrials")
	local Cash = Instance.new("StringValue",leader)
	Cash.Name = "SpaceHighway"
	Cash.Value = ds:GetAsync(player.UserId) or "9999999999"
	ds:SetAsync(player.UserId, Cash.Value)
	Cash.Changed:Connect(function()
		ds:SetAsync(player.UserId, Cash.Value)
	end)
end)


game.Players.PlayerRemoving:Connect(function(player)
	ds:SetAsync(player.UserId, player.TimeTrials.SpaceHighway.Value)
end)

And for test, can we combine this one too?

local DataStore = game:GetService("DataStoreService")
local ds = DataStore:GetDataStore("SpaceTurnpike")

game.Players.PlayerAdded:Connect(function(player)
	local leader = player:WaitForChild("TimeTrials")
	local SpaceTP = Instance.new("StringValue",leader)
	SpaceTP.Name = "SpaceTurnpike"
	SpaceTP.Value = ds:GetAsync(player.UserId) or "9999999999"
	ds:SetAsync(player.UserId, SpaceTP.Value)
	SpaceTP.Changed:Connect(function()
		ds:SetAsync(player.UserId, SpaceTP.Value)
	end)
end)


game.Players.PlayerRemoving:Connect(function(player)
	ds:SetAsync(player.UserId, player.TimeTrials.SpaceTP.Value)
end)

If you can help, please let me know. Thanks, WE.

Oh and also can the DataStore be called TimeTrials?

Use a table.

Before even telling you how to combine the DataStores, it’s really critical to address your current bad use of DataStores. It’s sort of off topic but it’s worth pointing out now so that you don’t ask another question down the line why your DataStores are acting up.

  • You modify the properties of created objects later, so don’t use the parent argument with Instance.new. Parent it after you set the properties.

  • ALWAYS use pcall when working with DataStore methods. The “GetAsync or X” idiom is dangerous and should be avoided. It’s hard to do any actual handling when it comes to DataStore issues (queues, outages or any other kind of error).

  • NEVER use DataStore methods in a Changed event EVER. DataStore methods should be called as few times in your game as possible. When it comes to handling data there are primarily four cases where you might use calls: joining, leaving, after a purchase and automatic saving.

So yeah there’s that. Going back to the topic at hand: use a table. You can combine all of your scripts, including the folder creation one, to make your code more predictable and avoid any of the unnecessary stuff like the WaitForChild calls in your code.

Y’know, something like this.

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")

local TimeTrialsDataStore = DataStoreService:GetDataStore("TimeTrials")

local TIME_TRIALS = {
    "SpaceHighway"
}

local function playerAdded(player)
    local trialsFolder = Instance.new("Folder")
    trialsFolder.Name = "TimeTrials"

    -- Used to avoid issues removing/adding trials
    local createdValues = {}

    for _, timeTrial in ipairs(TIME_TRIALS) do
        -- Not sure why you use StringValues for numbers
        local value = Instance.new("StringValue")
        value.Name = timeTrial
        -- Also not sure why this is the default
        value.Value = "9999999999"
        createdValues[timeTrial] = value
        value.Parent = trialFolder
    end

    local success, result = pcall(function ()
        return TimeTrialsDataStore:GetAsync(player.UserId)
    end)
    if success then
        if result then
            -- Assuming the return value is a table
            for trial, completionTime in pairs(result) do
                -- No value created, ignore entry
                if not createdValues[trial] then continue end
                createdValues[trial].Value = completionTime
            end
        end
    else
        -- Do some failure handling here, like adding them to a save block list
        warn("Data could not be loaded for user " .. tostring(player.UserId))
    end

    trialsFolder.Parent = player
end

local function playerRemoving(player)
    -- Just in case they leave before this exists or it gets modified
    local trialsFolder = player:FindFirstChild("TimeTrials")
    if not trialsFolder then return end

    -- Serialise the TimeTrials folder
    local values = {}
    for _, trialValue in ipairs(trialsFolder:GetChildren()) do
        values[trialValue.Name] = trialValue.Value
    end

    -- 'n save it
    local success = pcall(function ()
        return TimeTrialsDataStore:SetAsync(player.UserId, values)
    end
end

Players.PlayerAdded:Connect(playerAdded)
Players.PlayerRemoving:Connect(playerRemoving)
for _, player in ipairs(Players:GetPlayers()) do
    playerAdded(player)
end

This is rough and untested code so learn from it or copy it at your own discretion. Debugging is in your hands as well, this isn’t necessarily intended to be a spoonfeeding of code but just an example of what you can do if you’re looking to unify your system.

3 Likes