How should I store banned players? (Datastores)

I’ve been using the Roblox BanAPI to ban players, and it’s been great, although I want to be able to see the banned players inside of a GUI. But, if I simply just created a frame for every key inside of a datastore, it would very quickly lag the client if there are lots of keys.

I thought about using a OrderedDataStore, the only problem with that is that I can’t update multiple values at once, so if I wanted to ban a list of users (max being 50), it would very quickly reach the datastore rate-limit.

So I came to my next solution, “normal” datastores. This is great, but the only problem is that I can’t sort the data by the time the player was banned, and I might have to make some sort of custom pages thing.

Limitations

  • I want to be able to search for banned users from their UserId, Username, the moderators Id, and the moderators username from a GUI
  • It should be reasonably fast, and not lag the client or server.

The only solution I can come up with is making the key of the datastore hold the username, userid, moderator username, and moderator id. I just wanted to get some other opinions before I came up with a final solution. <3

I’d store bans in a normal datastore using UserId as the key and put all the info (username, mod ID, reason, timestamp, etc.) inside the value.

Then keep a separate array-style key like BanLog_Index where you store a list of UserIds or timestamps so that then you can sort them. You just append to that list when a new user is banned.

That way you don’t hit write limits (w. OrderedDataStores), and you can still paginate/sort by ban time without scanning all keys. You’d just fetch the latest chunk of the index and then pull the details by UserId.

1 Like

Would I just use GetUserInfosByUserIdsAsync with every userId from the OrderedDataStore? And then when they click “show more” get the rest of the info from the normal datastore?

The gui will show the username and the date the ban expires / if it was revoked. I’m guessing I can do this by just seperating the userId and timestamp with a dash for the key.


would this be a seperate OrderedDatastore?

Also, since I want to be able to search for the mod username, moduserid, userid, and username for the bans, wouldn’t that mean I would have to run :GetAsync() for each userId in the BanLog_Index? array

You wouldn’t use an OrderedDataStore for BanLog_Index. Just use a regular key in a standard DataStore and store an array of UserIds (or something like “UserId-Timestamp” if you want to make them unique). This way you control the order manually, so you avoid the write limits that OrderedDataStores have.

For showing usernames in the GUI, using Players:GetUserInfosByUserIdsAsync() is good, just fetch the UserIds for the current page from your index, then get their ban data from the main store.

You don’t need to load every ban at once. Just paginate by slicing the index array and loading each user’s info as needed.

To support searching you could make extra keys like UsernameToUserId or ModIdToUserIds. Or just load the index into memory and filter it there which works fine unless you’re dealing with thousands of entries. Do you think this would work for what you’re imagining?

1 Like

Yes! One last question though, when you say paginating do you mean like inside of a datastore have the keys be 1, 2, 3, 4, 5, with something like 50 values in each? If so how would I know how many existing pages there are, and when to make a new page if the newest page is full?

Yeah, you should create a new page key once the current one hits 50 entries. So if Page_1 is full, start writing to Page_2, then Page_3, etc.

Just keep a separate key like PageCount or LastPageIndex to track how many pages exist. That way you don’t have to scan all the pages every time you add a ban and you just get the latest one and append to it or create a new one if it’s full.