Is there a better way to approach this way of rating system?

This rating system I made uses messaging service to send the votes from one server to another, so that all the servers have the same rating data.

I was wondering if there was a better way to approach doing this?

--> Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local DataStoreService = game:GetService("DataStoreService")
local MessagingService = game:GetService("MessagingService")

--> Table
local Ratings = {}

--> Data Store
local DataStore = DataStoreService:GetDataStore("Car_Ratingssssss", "Ratingsssssss")

--> Load Ratings
local Succ, Data = pcall(function()
	return DataStore:GetAsync("Rating_Cars")
end)

if Data ~= nil then
	Ratings = Data
end

--> Modules
local Math = require(ReplicatedStorage:WaitForChild("MathAddons"))

--> Remotes
local Remotes = ReplicatedStorage:WaitForChild("Remotes")
local GetRating = Remotes:WaitForChild("GetRating")
local Rate = Remotes:WaitForChild("Rate")
local Notify = Remotes:WaitForChild("Notify")

--> Topic
local Topic = "CarRate"

--> Message Recieved
MessagingService:SubscribeAsync(Topic, function(msg)
	local Str = tostring(msg.Data)
	local Splitted = string.split(Str, "/")
	
	local car = Splitted[1]
	local avg = Splitted[2]
	
	table.remove(Splitted, 1)
	table.remove(Splitted, 2)
	
	local RatingsTbl = {}
	
	for _, v in pairs(Splitted) do
		local UserId, Rate = unpack(string.split(v, "|"))
		
		RatingsTbl[tostring(UserId)] = Rate
	end
	
	if Ratings[car] ~= nil then
		for UID, Val in pairs(RatingsTbl) do
			Ratings[car].Ratings[tostring(UID)] = Val
		end
		
		local NumTbl = {}
		
		for _, v in pairs(Ratings[car].Ratings) do
			table.insert(NumTbl, v)
		end
		
		Ratings[car].Average = math.clamp(Math.avg(NumTbl), 1, 5)
		Ratings[car].Average = math.floor(Ratings[car].Average * 10) / 10
	else
		Ratings[car] = {
			Ratings = RatingsTbl,
			Average = 0
		}
		
		Ratings[car].Average = math.clamp(Math.avg(Ratings[car].Ratings), 1, 5)
		Ratings[car].Average = math.floor(Ratings[car].Average * 10) / 10
	end
end)

GetRating.OnServerInvoke = function(player, CarName)
	if Ratings[CarName] == nil then return 0 end
	
	return Ratings[CarName].Average
end

Rate.OnServerEvent:Connect(function(player: Player, Car, Rating)
	if Rating <= 0 then return end
	if Rating > 5 then return end
	
	local UserId = player.UserId
	
	if not workspace:WaitForChild("Cars"):FindFirstChild(Car) then
		Notify:FireClient(player, "Cannot vote for a non-existant car!", Color3.fromRGB(255, 97, 97), 3)
	end
	
	if Ratings[Car] ~= nil then
		if Ratings[Car].Ratings[tostring(UserId)] ~= nil then
			Ratings[Car].Ratings[tostring(UserId)] = Rating
		else
			Ratings[Car].Ratings[tostring(UserId)] = Rating
		end
		
		local NumTbl = {}
		
		for _, v in pairs(Ratings[Car].Ratings) do
			table.insert(NumTbl, v)
		end
		
		Ratings[Car].Average = math.clamp(Math.avg(NumTbl), 1, 5)
		Ratings[Car].Average = math.floor(Ratings[Car].Average * 10) / 10
	elseif Ratings[Car] == nil then
		Ratings[Car] = {
			Ratings = {
				[tostring(UserId)] = Rating
			},
			Average = Rating
		}
	end
	
	Notify:FireClient(player, tostring("You Voted " .. tostring(Rating) .. " Star(s) On The " .. Car .. "!"), Color3.fromRGB(85, 170, 127), 3)
end)

Players.PlayerRemoving:Connect(function()
	DataStore:SetAsync("Rating_Cars", Ratings)
end)

game:BindToClose(function()
	DataStore:SetAsync("Rating_Cars", Ratings)
end)

while task.wait(30) do
	for Car, Values in pairs(Ratings) do
		local RatingsTbl = Values.Ratings
		local Avg = Values.Average
		
		local str = tostring(Car .. "/" .. tostring(Avg))
		
		for UserId, Val in pairs(RatingsTbl) do
			str = tostring(str .. "/" .. tostring(UserId) .. "|" .. tostring(Val))
		end
		
		MessagingService:PublishAsync(Topic, str)
	end
end