Saving multiple tables to datastore

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? I’m working a moderation system for my game and I want to log all the moderation actions so my moderation team can check previous actions taken on a User like warns, kicks and bans.

  2. What is the issue? If I save a warning to the datastore and there’s already a existing one then it just replaces the old one.

  3. What solutions have you tried so far? I havent tried a lot because I have no idea how DataStore works.

This is the code I made:

local HS = game:GetService("HttpService")
local DS = game:GetService("DataStoreService"):GetDataStore("DS_modLog2")

local Event = game:GetService("ReplicatedStorage"):FindFirstChild("ExecuteMod")

Event.OnServerEvent:Connect(function(plr, Type, Reason, Username, UserId, Time)
	if plr:GetRankInGroup(123456) >= 50 then
		local key = "Log_"..UserId
		if Type == "Type: Warn" then
			local Data = {
				"Warn",
				plr.Name,
				plr.UserId,
				Reason,
				DateTime.now()
			} local String = HS:JSONEncode(Data)
			
			local Success, Failure = pcall(function()
				DS:SetAsync(key, String)
			end)
			
			if Success then
				warn("Success")
			else
				warn("Fail")
			end
		end
	end
end)
1 Like
  1. You don’t need to JSONEncode the table. As long as it only contains numbers, strings, and/or booleans (which is all the DataStore accepts anyway), it will save just fine.
  2. You can add to a table of the player’s warnings, bans, kicks, etc.
  • Get the already existing one
  • add another one
    so you could end up with something like:
local playerMod = {
    [1] = {
        --player's first warning data
    },
    [2] = {
        --player's second warning data
    }
}

If I don’t JSONEncode the table it gives me this error: DataStoreService: CantStoreValue: Cannot store Array in data store. Data stores can only accept valid UTF-8 characters. API: SetAsync, Data Store: DS_modLog2

Also can you tell me how I would check the datastore if there’s a already existing one so I could place a [1] or [2] after it so it doesnt replace it?

I believe the issue is that you’re trying to store DateTime.now() which is a DateTime (userdata) type. Instead you should try saving “DateTime.now().UnixTimestampMillis” which is a number type.

Like @MuPower said, you need to save it as a number. You could also try os.date(), but I don’t know if that’s a number or not. You could also try paring it with tostring(), or have a go experimenting with os.time().

In terms of checking for a warning already, whenever you make the warning, try this:

local playerMod
local success, err = pcall(function()
    playerMod = yourStore:GetAsync(key)
end)
if playerMod == nil then --first time
    playerMod = {
        [1] = { --set it as the first one
            --your warning here
        }
    }
else --not first time
    local alreadyExisting = #playerMod --get already existing warnings
    local newIndex = alreadyExisting + 1 --create a new warning with the index after the existing ones
    playerMod[newIndex] = { --write the warning in
        --your warning here
    }
end

--then, save it back to the store:
local success, err = pcall(function()
    yourStore:SetAsync(key, playerMod)
end)

This is not tested. Hope it helps, though.

Firstly to store multiple data in a DataStore you can use scopes.


local DataStore1 = DataStoreService:GetDataStore("DataStore", "Scope1")
local DataStore2 = DataStoreService:GetDataStore("DataStore", "Scope2")

Also you cannot store tables as values, you have to convert them to string using tostring() then assign as value.

To use them as table after you have to split the curly brackets then trim the whitespace. And convert it to a table splitting with commas (,).


To set a value to the latest index you can use table.insert() method. This will bind the data to latest index, if the table is empty then it will assign it to index of 1.

Oops! Kinda forgot about table.insert(). As for scopes, I don’t often use the other parts of the DataStore so I don’t really use them.

As for storing tables as values, I don’t really get what you’re trying to say, but I know that tables/dictionaries consisting of numbers, strings, and booleans can be saved.

I mean you can’t set a table instance as a value of DataStore. If you don’t understand what I mean by value then the output you get when you use DataStore:GetAsync() is the value, or you can call it data.

Also you can investigate to documentation below:
Data Stores | Documentation - Roblox Creator Hub

But if you still want to store a table inside a DataStore then you should use custom functions to serialize and deserialize.

Serialize is basically converting it to string and you can use built-in method


tostring({Value1, Value2, Value3})

will return below but as a string, so it won’t be a table anymore

{Value1, Value2, Value3}


Deserialize is basically converting string to table.


local function StringToTable(StringToConvert)
	local OutputTable = {}

	--Remote first curly bracket
	StringToConvert = StringToConvert:sub(2, #StringToConvert)

	--Remove last curly bracket
	StringToConvert = StringToConvert:sub(1, #StringToConvert - 1)

	--Trim whitespaces
	StringToConvert = StringToConvert:gsub("%s+", "")

	--Convert to table
	for Value in string.gmatch(StringToConvert, "[^,]+") do
		table.insert(OutputTable, Value)
	end

	return OutputTable
end

The function above works perfectly but it only can convert basic tables, so if your table will contain table values then it won’t work properly.

I know you can’t save a table of instances. You can save a table of booleans, strings, and numbers perfectly fine, so I don’t see the point in converting it to a string?

1 Like

Oh really? I didn’t know that we can store a table of other types.
I think I didn’t have to store these types of values.

Whether thanks for the missing information.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.