Thanks for the quick responses! I’m not free at the moment, but I will give a look at :UpdateAsync() and the threads posted when I return home.
Caching is absolutely your best friend in an instance where you need to modify data frequently.
Retrieve the information you have in a DataStore and hold it in a ModuleScript designed to keep track of player data. If clients need access, use remotes to interact with it. Allow the module to expose methods for getting, setting and updating data for the server. Modify data in said ModuleScript as opposed to constantly using DataStore methods - there are very few cases where you need to upload data to the DataStore (saving, loading, after purchases, players leaving, autosaving, manual saving, etc).
Also, there is quite an informative discussion that occurred in the above thread that Operatik linked. Make sure to read that carefully - simply switching SetAsync to UpdateAsync isn’t enough. Both are still useful but it’s important to know when and the distinction between how they work.
There’s nothing wrong with using SetAsync
. If you don’t need to compare the new value to the old value, it’s perfectly fine to just set the value. You should only ever use UpdateAsync
if your new value depends on the current value. An example of where to use UpdateAsync
would be if you’re incrementing the value and would otherwise have to GetAsync
immediately before your SetAsync
.
I have been experimenting a bit today, and so far I’ve found that caching the user’s data in a series of DataValues within some folders in ServerStorage have helped tremendously with altering data rapidly. I do not however see any inherent advantages to using UpdateAsync over SetAsync at the moment, as these DataValues are uploaded as a table to the DataStore every minute or so, and upon leaving/shutdown. I have yet to test out the datastore2 module linked above, because honestly modules are still pretty beyond me, but it sounds very reliable in regards to avoiding data loss, so I will continue to research that in the meanwhile.
I fought a lot for the usefulness and merit of UpdateAsync in the thread that @Operatik posted.
While there’s a lot to talk about in regards to the use of either function, one key difference I can pull out is that SetAsync may potentially be unreliable. GetAsync caches, so that means that what you push from SetAsync may not necessarily be what comes out from a GetAsync call. UpdateAsync does not cache and provides a live value to be used as the sole argument in transformFunction.
This all being said, you should probably be fine the way you’re using SetAsync and your current data set. I don’t think you need the previous value and hopefully you aren’t calling GetAsync too frequently either (or really at all aside from first load or where necessary).
I really do encourage you at some point in the future to move over to storing data via ModuleScripts as instances can become costly once attached to the DataModel. Modules are very handy once you get the hang of how to implement them. Writing them is not hard, but determining best practices on a case-by-case scenario is where you’ll find most effort will be put into.
On wiki it states that SetAsync can be hazardous because it overwrites data, UpdateAsync is a much safer method as it updates not overwrites data, personally I’ve experienced a ton of dataloss issues with SetAsync and I’ve just recently switched to UpdateAsync.
For player data, when the player leaves, the data could be completely different (and usually will be). I don’t see any reason to compare new and old values when the new value could be completely different. Of course, you should do checks to make sure all your data’s there before you save, but you don’t have to use UpdateAsync to make sure what you’re saving isn’t nil.
Well you see, the whole point of UpdateAsync isnt about comparing 2 values, thats just a bonus, what it’s really about is updating data not over writting it, much harder to lose data that way.
From what I understand, UpdateAsync is basically like a version history system. What @Complextic is saying is that UpdateAsync will basically cache the old value. If there is no old value, the code won’t fail, there will just be no old value to cache. SetAsync doesn’t do this, it only overwrites the value. The reason UpdateAsync is important is because if it were to fail, it can always fall back on the old value which prevents complete data loss. Having 90 points on the leaderboard instead of 100 points is better than losing all of your points.
Yeah thats basically the entire point behind UpdateAsync is if it cant make a new save instead of losing all of the data it will have the previous data it can fallback on.
Not necessarily. UpdateAsync isn’t remotely like a version history. It simply passes a non-caching value to transformFunction, that value being what the DataStore key currently has entered.
Code can still fail, regardless of whether you have a value assigned to a key or not. Either the data assigned to a key will be passed as oldValue or nil in the case of no value.
Depending on how you use UpdateAsync, you can experience the exact same data loss that you do with SetAsync.
Also, surprisingly, some tests last night after a discussion on UpdateAsync revealed interesting behaviour. It depends on what kind of failure you’re talking about.
As far as transformFunction goes, if you pcall UpdateAsync and transformFunction fails, transformFunction will throw an error but pcall will actually return success and nil. Depending on if you use the return from UpdateAsync, this could be detrimental.
You are way more likely to experience dataloss with SetAsync than you are with UpdateAsync and I speak from experience.
I’m not sure how it’s “much harder to lose data” with UpdateAsync
. The only benefit I can see with UpdateAsync
is if you’re saving the old data to another place or don’t check if the value you’re setting is nil. If there’s any other benefits that make it easier not to lose data, I’d be much more interested in using it. I just don’t see any major benefits.
I mean it literally says it in the screenshot above that SetAsync() can be hazardous.
Yes, but it doesn’t explain at all why. In the case of user data, you don’t necessary need to consider the old value; if the user’s in the server, the values you have been using in that server should be correct anyway.
It is hazardous because it overwrites data, meaning it completely erases the old data that was there previously.
Yes, why do you care about the old data? That’s what I have been asking the entire time.
We care about old data because if the SetAsync() errors then all the data is lost, but if it errors with UpdateAsync() the old data was not erased so it has something to fallback on.
That is completely irrelevant. If the SetAsync
errors, it makes no sense for it to delete the data. If it can’t access Roblox servers, how would it delete the data?