So, I have been tasked with implementing a 'retweet'-like functionality in an app (iOS, Swift), using Parse.
This has been asked before here, but that's a) pretty high-level and b) I get the task at hand - I am not necessarily asking for help on the architectural decisions, though if it seems that I am obviously missing something, I'm happy to accept feedback.
My app has CAUSES which are each created by a USER. There is also a FOLLOW table with a TO and a FROM user. So to start, I simply query the CAUSES table, with the constraint that the USER who posted should match the objectId of a TO user (where the current user is the FROM user) in the FOLLOW table. More succinctly:
let getFollowedUsersQuery = PFQuery(className: Constants.kParseClassFollowers)
getFollowedUsersQuery.whereKey(Constants.kParseFieldFromUser, equalTo: PFUser.currentUser()!)
let causesQuery = PFQuery(className: Constants.kParseClassCauses)
causesQuery.whereKey(Constants.kParseFieldFromUser, matchesKey: Constants.kParseFieldToUser, inQuery: getFollowedUsersQuery)
causesQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let causes = objects {
for cause in causes {
// populate the tableview cells, etc.
}
}
})
Now I have all the causes from users that i follow... that's all pretty standard.
Here's where it gets tricky.
Each CAUSE also has a Relation called SUPPORTERS. Now I need to architect a way to get all the CAUSES from people that I do not follow, but which have in their list of supporters a user that I follow.
I have yet to find an elegant solution, though I am approaching a 'brute force' one, and it is so cumbersome and verbose that the better half of my programmer's brain is screaming at me like Susan Powter...
Here's a sample:
let retweetQuery = PFQuery(className: Constants.kParseClassCauses)
retweetQuery.orderByDescending(Constants.kParseFieldCreatedAt)
retweetQuery.whereKey(Constants.kParseFieldFromUser, notEqualTo: PFUser.currentUser()!)
retweetQuery.whereKey(Constants.kParseFieldFromUser, doesNotMatchKey: Constants.kParseFieldToUser, inQuery: getFollowedUsersQuery)
retweetQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let causes = objects {
for cause in causes {
let supporterRelations = cause.relationForKey(Constants.kParseClassSupporters)
let supporterQuery = supporterRelations.query()
supporterQuery.findObjectsInBackgroundWithBlock { (supporters, error) in
if(error == nil && supporters?.count > 0) {
for supporter in supporters! {
let user:PFUser = supporter as! PFUser
getFollowedUsersQuery.whereKey(Constants.kParseFieldToUser, equalTo: user)
getFollowedUsersQuery.whereKey(Constants.kParseFieldFromUser, equalTo: PFUser.currentUser()!)
getFollowedUsersQuery.findObjectsInBackgroundWithBlock({ (results, error) -> Void in
if(error == nil && results?.count > 0) {
for result in results! {
// do stuff
}
}
})
}
}
}
}
}
})
Now, this is pure madness, and incredibly wasteful (especially considering how Parse calculates the free tier - I feel this could really contribute heavily to my API limit if pushed to production).
Having already done two queries, I redo one entirely, then perform another query for each cause on the SUPPORTER Relations, then do another query on each user in that Relation to see if I follow them... and once I have that information, I need to loop through that User's supported causes (because of the asynchronous returning of the Parse queries, I don't feel that I can just reach back into the parent loops at all) ... which I haven't implemented yet, cause I'm about to throw in the towel - there has to be a better way!
I hope that I'm missing a strategy here...
Aucun commentaire:
Enregistrer un commentaire