Hello, after I learnt why UpdateAsync() is safer than SetAsync(). So I tried to make a code using UpdateAsync(), and I need some reviews on if I did my code right, and any optimizations for the code. Thanks in advance.
local DSS = game:GetService(“DataStoreService”)
local CashDS = DSS:GetDataStore(“CashDataStore”)
local function UpdateData(oldVal)
local previous = oldVal.Cash or {oldVal.Cash = 0)
if oldVal.Cash == previous then
oldVal.Cash += 20
else return nil end
end
game.Players.PlayerAdded:Connect(function(plr)
local key = plr.UserId
local folder = Instance.new(“Folder”)
folder.Name = “leaderstats”
folder.Parent = plr
local cash = Instance.new(“IntValue”)
cash.Name = “Cash”
cash.Parent = folder
local DataTable
local success, failure = pcall(function()
DataTable = CashDS:GetAsync(key)
end)
if success then
cash.Value = DataTable.Cash or 0
else return error(“Failed to get DataStore. Error code: ”..failure) end
end)
game.Players.PlayerRemoving:Connect(function(plr)
local key = plr.UserId
local DataTable = {
Cash = plr.leaderstats.Cash.Value
}
local success, failure = pcall(function()
CashDS:UpdateAsync(key,UpdateData(DataTable))
end)
if success then
print(“Successfully saves player’s data.”)
else return error(“Failed to save data. Error code: ”..failure) end
— code is untested yet since I’m on mobile.
This line won’t work because then you’d be calling UpdateAsync with the second parameter as a non-function value (this would evaluate to use the return value of UpdateData for the TransformFunction). You only need to be passing UpdateData here. Remember that your functions are variables.
CashDS:UpdateAsync(key, UpdateData)
Looks fine otherwise, I guess. There’s just simple recommendations that can be made.
Assign the anonymous function being connected to PlayerAdded to a variable. Connect it later and run it for existing players. If your thread yields or doesn’t run in time, players in the server before this code runs will not get data.
Parent the Folder to the player after you finish working with DataStores. Your current order is [1], you should instead make it [2]. List is below.
pcall is a callback, return the value instead of using another variable. Example is below. Doesn’t really make a difference but better to use pcall as it’s intended to be used when it comes to DataStores - this variable pattern is really weird.
DataStore Flow:
Current: Create folder → Parent folder → Create cash → Parent cash → Get data → Set cash Change to: Create folder → Create cash → Get data → Set cash → Parent cash → Parent folder Why: You’re just modifying pieces of memory. Always parent after you make your changes.
pcall use:
-- Current
local DataTable
local success, failure = pcall(function ()
DataTable = CashDS:GetAsync(key)
end)
-- Change to
local success, result = pcall(function ()
return CashDS:GetAsync(key)
end) -- *
* result will either be what GetAsync returns or a string representing a caught exception depending on what success returns. In case of DataStore outage where pcall success is true but GetAsync returns unexpected results, this may either be an issue with your code or on Roblox’s side.
Since this function validates the data, it should be used in favor of SetAsync() when there’s a chance that more than one server can edit the same data at the same time.
Pretty much does exactly what it says on the tin. Two or more servers may have the potential to update a DataStore key’s value, so UpdateAsync performs validation. That is, certain conditions need to be met for the update to be successful internally.
As a developer, the part most takeaway for you should be the last bit of that sentence, which is that UpdateAsync will properly handle cases of multiple servers updating data and allow you to transform (modify, change) the data directly. SetAsync, on the other hand, just indiscriminately sets a key’s value to whatever you pass and then it’s done. You don’t get the chance to change data.
A good way to think about DataStore functions and how to use them is also in terms of their names.
GetAsync will get the value of a key.
SetAsync will set the value of a key.
UpdateAsync will update the value of a key.
What’s the difference between setting and updating? An update is iterative upon a previous data point, which in UpdateAsync’s case is the single parameter given to the transform function (in your code sample, the transform function is UpdateData. A setting is making something into whatever you give it, but it’s not iterative and doesn’t care about what was there before.
local success, err = pcall(function()
DataStore:UpdateAsync(plr.UserId, function(OldValue)
return NewValue
end
end)
UpdateAsync considers old data before saving. So if you want to make something like, lets say a rebirth system. You can use UpdateAsync to check that the new data that should be saved is more than that of the old value. So if you check that the old value is more than the new value, you can just save the old value like:
DS:UpdateAsync(plr.UserId, function(OldValue)
if not OldValue then
OldValue = 0
end
if NewValue > OldValue then
return NewValue
else
return OldValue
end
end)