Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
3

[HELP] What are keys in datastores?

Asked by 5 years ago
Edited 5 years ago

I know what datastores are, and I have a pretty basic understanding of them, but the one thing I have never understood are keys

0
*accept answers to get yourself points and for the other person**. Anyways, yeah I hope you get the hang of Datastorage. It's complicated. Sometimes demonstrations are hard to get use to TheePBHST 154 — 5y

3 answers

Log in to vote
5
Answered by 5 years ago

Your question is pretty vague, however, I will still explain from what I can tell you are asking.

Let's think of a datastore as a place with multiple boxes. Each box is locked, and to access it you need a 'key'.

So, in our game (as an example), we have a different key for every player. This means that each player has their own box to store data in. Let's make the key the player's user id because every player has a unique one.

Now, our player has a place in that datastore to have data stored in or retrieved from. How do we access it? The key required to open the box must have the same name as the box itself, so that way no other player can access another player's data.

In our script, we can access the 'box' and retrieve data by using :GetAsync(), and set data using :SetAsync().

In a script, it would look like this:

local datastoreService = game:GetService("DataStoreService") -- Get the API
local datastore = datastoreService:GetDataStore("TestDataStore") -- Can be anything, for this example it is 'TestDataStore'

local key = "123456789" -- Just an example, in a real scenario you would want it to be the player's userid

datastore:SetAsync(key, 5) -- We have stored the integer '5' into the box '123456789' in our datastore

print(datastore:GetAsync(key)) -- This will print '5', because that is the data stored

Here is also a working example of how you can use datastores to save points:

local datastore = game:GetService("DataStoreService"):GetDataStore("PointsStore")

game.Players.PlayerAdded:connect(function(player)
    local leaderstats = Instance.new("Folder", player)
    leaderstats.Name = "leaderstats"

    local points = Instance.new("IntValue", leaderstats)
    points.Name = "Points"

    local key = player.UserId -- Unique key for each player
    local data = datastore:GetAsync(key) or 0 -- If there is no data stored, make it 0

    points.Value = data
end)

game.Players.PlayerRemoving:connect(function(player)
    local key = player.UserId -- Again, unique key

    datastore:SetAsync(key, player.leaderstats.Points.Value)
end)
0
Thanks so much! Ak_lixio 17 — 5y
Ad
Log in to vote
3
Answered by 5 years ago
Edited 5 years ago

I've transferred this answer over to a gist, if you'd like to share this answer with someone else, direct them here.

What are data stores?

Data stores are a service offered to developers which allow them to save data and fetch it from any server in the universe (game).

How are data stores structured?

Data stores are structured similarly to dictionaries/records. They consist of key-value pairs. Each key is unique and acts like a "header" or "identifier", if you like, and can hold a value that can be converted or serialised into JSON. This means that you cannot explicitly set a key's value to a userdata (which includes but is not limited to Instances), and can only save primitive types (numbers, booleans, strings and tables containing only these types).

Example

  • PlayerDataStore
    • 98401192 | {Currency = 100, IsAdmin = false}
    • 46383457 | {Currency = 238, IsAdmin = true}

The above example is a representation of a data store that holds a collection of key-value pairs which hold player data. The key should be a unique identifier relevant to the corresponding player, hence you can use the player's UserId.

Making requests to a data store

Getting Data

You can fetch data from a data store using the GetAsync method. It takes a string as it's key parameter, which will be used as a unique identifier for your data.

API

  • Method

    GetAsync(string Key)

  • Sample call

    local PlayerDataStore = game:GetService("DataStore"):GetDataStore("PlayerDataStore")
    
    game.Players.PlayerAdded:Connect(function(player)
        local playerData = PlayerDataStore:GetAsync(player.UserId)
    end)
    

Setting Data

You can set a key's value using the SetAsync method. It takes the key whose value will be set, and a primitive value as the arguments.

API

  • Method

    SetAsync(string Key, variant Value)

  • Sample call

    local PlayerDataStore = game:GetService("DataStore"):GetDataStore("PlayerDataStore")
    
    local ServerPlayerData = {}
    
    game.Players.PlayerRemoving:Connect(function(player)
        PlayerDataStore:SetAsync(player.UserId, ServerPlayerData[player])
    end)
    

There are other member functions available to us which allow us to "Update" a data store field, but these are rarely needed and you can find them on the wiki here.

Error handling

Data store requests are prone to errors, and to have good design you must be able to handle errors effectively whenever they happen. Something as simple as wrapping the request around a pcall() and repeating the request after an arbitrary interval should do the trick.

Throttling

Data stores are assigned a request budget. If the number of requests made exceed this budget, the data store will throttle.

Sample code

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

local PlayerDataStore = DataStoreService:GetDataStore("PlayerDataStore")

local RETRY_LIMIT = 3
local RETRY_INTERVAL = 5

local function GetPlayerData(userId)
    local success, e = pcall(PlayerDataStore.GetAsync, PlayerDataStore, userId)

    -- Return player data if the request was successful.
    if success then return e end

    -- Check if the data store has throttled, if so, wait until the request budget is increased.
    while DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.GetAsync) < 1 do
        wait(1)
        warn("Data store budget depleted")
    end

    local currentRetries = 0

    -- Repeat the request until the request is successful or the request limit is reached.
    repeat
        wait(RETRY_INTERVAL)
        currentRetries = currentRetries + 1

        success, e = pcall(PlayerDataStore.GetAsync, PlayerDataStore, userId)

        if success then
            return e
        end
    until currentRetries == RETRY_LIMIT
end

Players.PlayerAdded:Connect(function(player)
    local playerData = GetPlayerData(player.UserId)
end)

Good design

You've probably found youtube videos that recommend you assign multiple keys to one specific value, even the wiki is guilty of this:

DataStore:SetAsync(player.UserId .. "_cash", player.Cash.Value)

It's simply bad design, you should be saving one dictionary per player, which contains all of the player's data. This reduces the total number of requests made, and consequently reduces the risk of throttling. This method also allows for scalability.

Here's a template or schema (blueprint of a data store) that one may use to save player data:

local PlayerDataSchema = {
    General = {
        Currency = 0,
        Experience = 0
    },
    Moderation = {
        AdminStatus = "Normal",
        ModerationHistory = {},
        ModerationStatus = "None"
    },
    PurchaseLog = {}
}

If you're familiar with OOP you could also save an object, do whatever is intuitive for you.

Closing remarks

Remember to maintain good error handling, scalability and always design your data stores intuitively. If you're game is in production and your data stores are designed poorly, you may have issues later down the line.

Log in to vote
1
Answered by
TheePBHST 154
5 years ago

Keys in DataStorage are basically different Storage for different people. So a Key would be like Player1 and another would be Player2

Answer this question