My current paradigm for handling DataStores involves using a GetAsync request when a player joins to load their data and a SetAsync request if they have no data stored. This is represented in code as the following example (I don’t really like my example and how it uses raw data):
Code sample with Get-Set combination
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local UserDataStore = DataStoreService:GetDataStore("UserDataStore")
local DataCache = {}
local function GetDataTemplate()
return {
A = 1,
B = 2,
C = 3,
}
end
local function handlePlayer(Player)
local success, result = pcall(UserDataStore.GetAsync, UserDataStore, Player.UserId)
if success then
if result then -- No ternary short circuiting for a reason
DataCache[Player.UserId] = result
else
local InitialData = GetDataTemplate()
DataCache[Player.UserId] = InitialData
local success = pcall(UserDatastore.SetAsync, UserdataStore, Player.UserId, InitialData)
end
else
-- I don't actually do this, this is terrible.
Player:Kick("Data fetch failure. If this happens repeatedly, contact developer.")
end
end)
Players.PlayerAdded:Connect(handlePlayer)
for _, Player in pairs(Players:GetPlayers()) do
handlePlayer(Player)
end
Recently though, I’ve been thinking about UpdateAsync and it’s uses in my codebase though. One of the beauties of UpdateAsync is that it serves as both a Get and Set request while only spending an UpdateAsync request and the Get part of it is non-caching. So, I’ve thought about using this as opposed to my disgusting Get-Set combination.
Code sample with UpdateAsync
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local UserDataStore = DataStoreService:GetDataStore("UserDataStore")
local DataCache = {}
local function GetDataTemplate()
return {
A = 1,
B = 2,
C = 3,
}
end
local function handlePlayer(Player)
local success, result = pcall(UserDataStore.UpdateAsync, UserDataStore, Player.UserId, function(old)
if old then
return old
end
return GetDataTemplate()
end)
if success then
DataCache[Player.UserId] = result
else
Player:Kick("No data") -- Bad
end
end)
Players.PlayerAdded:Connect(handlePlayer)
for _, Player in pairs(Players:GetPlayers()) do
handlePlayer(Player)
end
This is an almost blatant abuse and misusage of UpdateAsync, though I feel as though I get better usage by taking advantage of that non-caching old value and handle both old and new data all in one go, while also ensuring data saves after “loading”.
Any thoughts about this paradigm? I haven’t really looked into depth about potential bottlenecks, improper usages or problems with doing this.