patternMinor
Data model code review for iOS app
Viewed 0 times
iosappmodelforcodedatareview
Problem
I'm new to iOS development and I'm having trouble figuring out how to efficiently load my app's data at launch time. My app consists of a UITableView that is populated with a list of songs. Each cell displays data about the song: current user rating(if rated) and avg. user rating (avg. rating of all users). I'm using Parse for my backend data storage.
At launch time, my app runs two queries. The first query fetches songs to populate the table. It then calculates the avg. user rating (my backend schema includes count objects: rating1_count, rating2_count, etc. which are incremented when the user rates a song). It also orders the songs into separate data model arrays: topTracksOfTheWeek, topTracksOfTheMonth, topTracksAllTime.
The second query fetches all of the rated songs by the current user. It then compares this query to the first query to embed the user rating data into the first query to form the app's data model.
I'd like to limit the first query to 50 songs to optimize load time. However, with my current data model, I need to query all of the songs in my database to calculate all of the avg. user ratings and then order the songs into the topTracks arrays.
The only solution I can come up with is running a server-side script periodically to calculate the avg. user ratings. I would have to create a new class in my database for the topTracks arrays that are ordered by the script. In my app, I would do a lazily do a third query for the topTracks arrays.
Here is my data model code:
```
{
PFUser *user = [PFUser currentUser];
NSMutableArray *ratings;
if (user) {
PFQuery *queryRatings = [PFQuery queryWithClassName:@"Ratings"];
[queryRatings whereKey: @"user" equalTo: user.username];
[queryRatings orderByDescending:@"createdAt"];
queryRatings.limit = 1000;
ratings = [NSMutableArray arrayWithArray:[queryRatings findObjects]];
}
else
[self displayLoginViewController];
At launch time, my app runs two queries. The first query fetches songs to populate the table. It then calculates the avg. user rating (my backend schema includes count objects: rating1_count, rating2_count, etc. which are incremented when the user rates a song). It also orders the songs into separate data model arrays: topTracksOfTheWeek, topTracksOfTheMonth, topTracksAllTime.
The second query fetches all of the rated songs by the current user. It then compares this query to the first query to embed the user rating data into the first query to form the app's data model.
I'd like to limit the first query to 50 songs to optimize load time. However, with my current data model, I need to query all of the songs in my database to calculate all of the avg. user ratings and then order the songs into the topTracks arrays.
The only solution I can come up with is running a server-side script periodically to calculate the avg. user ratings. I would have to create a new class in my database for the topTracks arrays that are ordered by the script. In my app, I would do a lazily do a third query for the topTracks arrays.
Here is my data model code:
```
- (void)getDataSource
{
PFUser *user = [PFUser currentUser];
NSMutableArray *ratings;
if (user) {
PFQuery *queryRatings = [PFQuery queryWithClassName:@"Ratings"];
[queryRatings whereKey: @"user" equalTo: user.username];
[queryRatings orderByDescending:@"createdAt"];
queryRatings.limit = 1000;
ratings = [NSMutableArray arrayWithArray:[queryRatings findObjects]];
}
else
[self displayLoginViewController];
Solution
Consider following scheme -
Each song has a key
Their initial value is 0.
When user rates a song with
And of course you increase numberOfRatings
With this approach you can utilize queries (query only the first 50 songs according to their averageRating etc.) for your topTracks chart views, and you do not have to query all songs just to count their average rating - at any given moment you have an up-to-date
Each song has a key
numberOfRatings and a key averageRating.Their initial value is 0.
When user rates a song with
newRating, you change the value of averageRating according to this formulaaverageRating = ((averageRating * numberOfRatings) + newRating) / (numberOfRatings + 1)And of course you increase numberOfRatings
numberOfRatings = (numberOfRatings + 1)With this approach you can utilize queries (query only the first 50 songs according to their averageRating etc.) for your topTracks chart views, and you do not have to query all songs just to count their average rating - at any given moment you have an up-to-date
averageRating stored for every song.Code Snippets
averageRating = ((averageRating * numberOfRatings) + newRating) / (numberOfRatings + 1)numberOfRatings = (numberOfRatings + 1)Context
StackExchange Code Review Q#15353, answer score: 3
Revisions (0)
No revisions yet.