How does scope in DataStores work?

Okay, I’m still a bit confused of how scope in DataStores work. As I go through the Roblox documentation, there’s a lack of explanation about it.

If you could illustrate how the hierarchy of a DataStore, how would it look like?

Maybe like this…?

DataStoreService
  Data Store Name
   Data Store Scope (optional)
    Data Store Key & Its Value

Any information/opinion about it will be helpful, thanks!

17 Likes

To be fairly honest, I dont think it’s often used this scope field.

Though I do think that your idea of scope is correct.

1 Like

I think it all boils down to personal preference, there’s nothing special about scopes in general from what I can tell. I do use them though, to keep things relatively clean.

For example:

::GetDataStore("GameUserData", player.UserId):GetAsync("Data");
::GetDataStore("GameUserData", player.UserId):GetAsync("LocalSettings");

Versus

::GetDataStore("GameUserData"):GetAsync(player.UserId).Data;
::GetDataStore("GameUserData"):GetAsync(player.UserId).LocalSettings;

EDIT
& in terms of hierarchy, it’d say it’s more so:

> DataStoreService
	> Name | Scope [<default> Global / <custom> Named]
	> Data

I can’t speak on how gracefully it’d scale with growth because I haven’t gotten to that point (although I can’t think of any reasons why it should be a problem), but here’s an excerpt on how I have it implemented:

local DatabaseKey = "GameUserData";

function Database:fetch(player)
	local UUID = tostring(player.UserId)
	
	local UserData = DataStore:GetDataStore(DatabaseKey, UUID) 

	if UserData then
		for attempt = 1, MaxGetAttempts do
			if attempt > 1 then
				warn(string.format("DataStore GET attempt [%d/%d]"), attempt, MaxGetAttempts);
			end
			
			local success, response = pcall(function()
				return UserData.GetAsync(UserData, "Profile")
			end)
			...

5 Likes

Yes, but in a hierarchical manner of the objects inside DataStoreService, where do you think scope would be located?

From your quote, I could say that scope acts like a sub-datastore where you can store your keys and its values in it?

Well then, is it possible to use scope to store more data, perhaps something like this?

GetDataStore("GameUserData", LocalSettings):GetAsync(player.UserId).SettingA
GetDataStore("GameUserData", LocalSettings):GetAsync(player.UserId).SettingB
GetDataStore("GameUserData", Data):GetAsync(player.UserId).NormalData
GetDataStore("GameUserData", Data):GetAsync(player.UserId).ExtraData
2 Likes

Oh yeah for sure, GetDataStore("GameUserData") uses the global scope, so the only difference with GetDataStore("GameUserData", "Scope") is that you’re using a new named scope as opposed to the default one.

::GetDataStore("GameUserData", "Data"):GetAsync(player.UserId).NormalData

^ …is valid

3 Likes

This is the whole database system:


(The scope is optional)

16 Likes

Scopes are just used to partition data into other sections. Think of them like subfolders in a DataStore. When you don’t specify a scope, your DataStore actually still uses a scope - the default scope, which is “global”. Specifying a scope puts a DataStore at the same level as one without it.

DataStoreService
 DataStoreName
  DataStoreKey
 DataStoreName Scope_global
  DataStoreKey
 DataStoreName Scope_safe1
  DataStoreKey

Think of it like your computer’s file system.

When you get a DataStore, you open up the main folder which is the first string you specify to GetDataStore. When you don’t specify a scope, it defaults to global and opens the global subfolder. If you specify a scope, it creates and opens the new folder which is the scope you set.

46 Likes

I don’t think there is an real hierarchy for datastores, scopes are basically just another way to distinguish datastores similar to data store names.

Whenever you get a datastore with a new data store name and scope it adds an instance under DataStoreService, could this mean a memory leak if you get a unique datastore for each player?

If someone still doesn’t understand here is it explained in Lua dictionary with a lot of data:

game:GetService("DatastoreService"):GetDataStore(Name, Scope):GetAsync(Key) = Data 

DataStoreService = {  -- game:GetService("DatastoreService")
	["NewData"] = {
		["global"] = {}, -- game:GetService("DatastoreService"):GetDataStore("NewData", "global")  or -- game:GetService("DatastoreService"):GetDataStore("NewData") 
		["Coins"] = { -- game:GetService("DatastoreService"):GetDataStore("NewData", "Coins") 
			["123456789"] = 0,  -- game:GetService("DatastoreService"):GetDataStore("NewData", "Coins"):GetAsync("123456789")
			["1576854665"] = 152 -- game:GetService("DatastoreService"):GetDataStore("NewData", "Coins"):GetAsync("1576854665")
		},
		["Diamonds"] = { -- game:GetService("DatastoreService"):GetDataStore("NewData", "Diamonds") 
			["123456789"] = 15, -- game:GetService("DatastoreService"):GetDataStore("NewData", "Diamonds"):GetAsync("123456789")
			["1576854665"] = 7595 -- game:GetService("DatastoreService"):GetDataStore("NewData", "Diamonds"):GetAsync("1576854665")
		},
		["Bank"] = { -- game:GetService("DatastoreService"):GetDataStore("NewData", "Bank") 
			["123456789"] = {
				["Coins"] = 15000000,
				["Diamonds"] = 1500000
			},
			["1576854665"] = {
				["Coins"] = 150,
				["Diamonds"] = 0
			}
		},
		["Stats"] = { -- game:GetService("DatastoreService"):GetDataStore("NewData", "Stats") 
			["123456789"] = {
				["TraveledDistance"] = 1520394,
				["KilledPeople"] = 15,
				["Died"] = 2
			},
			["1576854665"] = {
				["TraveledDistance"] = 150,
				["KilledPeople"] = 2,
				["Died"] = 15
			}
		}
	},
	["Data"] = {
		["global"] = { -- game:GetService("DatastoreService"):GetDataStore("Data", "global")  or -- game:GetService("DatastoreService"):GetDataStore("Data") 
			["123456789"] = 550,
			["1576854665"] = 15788,
			["785"] = 560,
			["1463566188"] = 150
		}
	}
}

Setting data:

game:GetService("DatastoreService"):GetDataStore("NewData", "Coins"):SetAsync("1576854665", 
6789)

Change:
DataStoreService = { 
	["NewData"] = { 
		["Coins"] = { 
			["1576854665"] = 152 
		}
    }
}
To:
DataStoreService = { 
	["NewData"] = { 
		["Coins"] = { 
			["1576854665"] = 6789
		}
    }
}
1 Like