using a friend system in ios parse swift - ios

I created a query with subquery
var userInitiated = PFQuery(className: "friends")
userInitiated.whereKey("friender", equalTo: PFUser.currentUser()!.username!)
var friendInitiated = PFQuery(className: "friends")
friendInitiated.whereKey("friendee", equalTo: PFUser.currentUser()!.username!)
// find friends of user
let friendQuery = PFQuery.orQueryWithSubqueries([userInitiated, friendInitiated])
friendQuery.findObjectsInBackgroundWithBlock ({ (objects:[PFObject]?, error:NSError?) in
if error == nil {
// cleanup
self.friendArray.removeAll(keepCapacity: false)
// STEP 2 Hold Recieved Data
// find objects that you queried for
for object in objects! {
self.friendArray.append(object.valueForKey("-----") as! String)
}
}
})
In the for object in objects part - I want to append the usernames that I got from the query but I only want to add the ones that aren't the current users username, how would I do that?

A is current User, B is one of A's friends. So what the (friender, friendee) pair in your "friends" class?
Both (A,B), (B,A)
one of (A,B) and (B,A)
In first case, you can just query friender equalTo currentUser
In second case, your query seems ok.

Related

Two constraints on one key in a Parse Query

I'm using Parse and my app is written in Swift. I have a golf app that allows a user to friend other users. The users can log their golf scores and then see their golf scores and their friend's scores in a leaderboard style tableViewController.
The problem I'm having is that Parse doesn't support two constraints on the same key in a query. I have a function that queries the users and their scores and stores them in an array of tuples (leadeboardData). I'm trying to querying the current user's PFRelation as well as the current user (variable "friendsRelation" and constant "friendQuery"). The class I query is the "GolfScorecard", which is where the scores are stored on Parse. I then called the "whereKey" method on the "golfer" key, which is where my user is stored under on Parse. I call "whereKey matchesQuery" for my friendsRelation query and then "whereKey equalTo" to try and get my current user. I then "includeKey" "golfer" so I can get the user info along with the score info. Any suggestions on how to go about this? I'm trying to do it all in one query but when the "whereKey" method is called on the same key ("golfer") the last one overrides the first one, which makes it only possible to get the friend info or the current user info but not both. I'm stumped how to include both. Thanks in advance.
Here is my function I call to make the query:
func loadLeaderboardData() {
leaderboardData.removeAll()
friendsRelation = PFUser.currentUser()?.objectForKey("friendsRelation") as? PFRelation
friendsRelation = PFUser.currentUser()?.objectForKey("friendsRelation") as? PFRelation
let friendQuery = friendsRelation?.query()
let query = PFQuery(className: "GolfScorecard")
query.whereKey("golfer", matchesQuery: friendQuery!)
query.whereKey("golfer", equalTo: PFUser.currentUser()!)
query.includeKey("golfer")
query.orderByAscending("score")
query.findObjectsInBackgroundWithBlock { (scoreCards: [PFObject]?, error: NSError?) -> Void in
if error == nil {
for object:PFObject in scoreCards! {
let golfer:PFObject = object["golfer"] as! PFObject
self.leaderboardData.append(object,golfer)
dispatch_async(dispatch_get_main_queue()) {
self.leaderboardTableView.reloadData()
}
}
} else {
print(error)
}
}
}
Thanks Paulw11 the orQueryWithSubQueries worked. The only issue it ended up presenting was my app was crashing with an error stating 'Key "username" has no data. Call fetchIfNeeded before getting its value.'...I don't think the Parse Query was coming back in time to load in the tableView that I was putting the data in. I ended up using the 'fetchIfNeededInBackgroundWithBlock' method inside of the cellForRowAtIndexPath call around the code where I was calling the 'username' data at. This allowed it to grab the data in the background if it didn't come back in time. This seemed to due the trick.
-Also I subclassed my queries, which is where the GolfScorecard & GolferProfile is coming from inside of my for-in loop.
-This is my new compound Query:
func loadLeaderboardData() {
leaderboardData.removeAll()
friendsRelation = PFUser.currentUser()?.objectForKey("friendsRelation") as? PFRelation
let friendQuery = friendsRelation?.query()
let friendScorecardQuery = PFQuery(className: "GolfScorecard")
friendScorecardQuery.whereKey("golfer", matchesQuery: friendQuery!)
let currentUserScorecardQuery = PFQuery(className: "GolfScorecard")
currentUserScorecardQuery.whereKey("golfer", equalTo: PFUser.currentUser()!)
let subQuery = PFQuery.orQueryWithSubqueries([friendScorecardQuery, currentUserScorecardQuery])
subQuery.orderByAscending("score")
subQuery.findObjectsInBackgroundWithBlock { (scoreCards: [PFObject]?, error: NSError?) -> Void in
if error == nil {
for object:PFObject in scoreCards! {
if let object = object as? GolfScorecard {
let golfer = object["golfer"] as! GolferProfile
self.leaderboardData.append(object,golfer)
dispatch_async(dispatch_get_main_queue()) {
self.leaderboardTableView.reloadData()
}
}
}
} else {
print(error)
}
}
}

Check if query key is nil Parse

So, I have a query in parse that has to find objects based on whether a key is equal to a certain object. Here is the few lines of code.
var gamesQuery = PFQuery(className: "Games")
gamesQuery.whereKey("challenged", equalTo: (PFUser.currentUser()!.objectId!))
gamesQuery.whereKey("challenger", equalTo: PFUser.currentUser()!)
However, when this query is ran, the query is occasionally found as nil due to the fact that there is no object that fits the search parameters.
Is there any check that I could run that could check if
gamesQuery.whereKey("challenged", equalTo: (PFUser.currentUser()!.objectId!))
is nil? Any help with this issue would be very appreciated.
Your current query is essentially an and - "find objects where challenged==current user and challenger==current user".
I think you are after an or query - "find objects where challenged==current user or challenger==current user". You can do this with a compound query in Parse -
let challengedQuery = PFQuery(className: "Games")
challengedQuery.whereKey("challenged", equalTo: (PFUser.currentUser()!.objectId!))
let challengerQuery = PFQuery(className: "Games")
challengerQuery.whereKey("challenger", equalTo: PFUser.currentUser()!)
let gamesQuery = PFQuery.orQueryWithSubqueries([challengedQuery, challengerQuery])
gamesQuery.findObjectsInBackgroundWithBlock {
(results: [PFObject]?, error: NSError?) -> Void in
if error == nil {
// results contains challenger and challenged games.
}
}

Querying the User table with a users objectId queried from another table

I'm trying to query my User table with the Users objectId queried from another table.
Here's my code:
func queryFriendsTable() {
var queryFriends = PFQuery(className: "Activity")
queryFriends.whereKey("type", equalTo: "friend")
queryFriends.whereKey("fromUser", equalTo: PFUser.currentUser()!)
queryFriends.includeKey("toUser")
var queryUserTable = PFUser.query()
queryUserTable!.whereKey("objectId", matchesKey: "toUser", inQuery: queryFriends)
queryUserTable!.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded
// Do something with the found objects
if let objects = objects as? [PFObject] {
for object in objects {
self.friendNamesArray.addObject(object["username"]!)
println(self.friendNamesArray)
}
}
}
}
}
Nothing is being returned when I run this query. I think the problem has to do with the fact that the toUser objectId in the Activity table is a pointer and not a string. (The toUser value I try to use in the matchesKey spot is a pointer)
So how can I get the objectId as a string from a pointer object using the inQuery method?
Your suspicions are correct. Parse won't find pointers when looking through the User's class. Instead what you'll need to do is create a string variable and set it equal to the result of queryFriends. So what that means is you'll have to run that query first, get the pointer back, and access it's objectId field as a string in order to use it in your following query.

ios swift parse: Having general issues with deep queries and their result data

I am still having problems understanding the correct way of handling deeper pointer structure in parse.
Example:
Card has pointer to CardSet
CardSet has pointers to Lesson and User
Lets say, I want to have all CardSets including
Lesson.name
Count of Cards for each CardSet
Can I query all this in just one query?
And have the data available without any additional fetchIfNeededInBackgroundWithBlock queries?
I know that I can get the Lesson with
var query = PFQuery(className: "CardSet")
query.whereKey("user", equalTo: PFUser.currentUser())
query.includeKey("lesson")
But that gives me only the lesson object, I can not access any data (like the col "name") from this class unless I use fetchIfNeededInBackgroundWithBlock what takes another query and of course more time to load.
What can I do to have all queried data
including all pointers columns
in order to pin this data to the local datastore with
PFObject.pinAllInBackground(objects, block: nil)
And not to forget, how can I query the number of cards related to the CardSet?
First I would recommend subclassing in Parse, it makes relationships between tables (pointers etc) clearer.
How to subclass the PFObjects you can explore this guide on parse
How to query the number of cards in CardSet
You need the CardSet from which you want the cards. (PFObject or subclassed PFObject).
Then just do this:
var query = PFQuery(classname: "cards")
query.whereKey("CardSet", equalTo: yourCardSetObject)
//Synchronously
query.findObjects().count
//Asynchronously
query.findObjectsInBackgroundWithBlock({
(objects, error) in
if error != nil {
println(error.localizedDescription)
return
}
objects.count
})
How to get the name of the lesson
As I said, it's recommended to subclass the PFObjects because you need to cast the objects what isn't really funny to debug and is horrible code.
I did it that way:
var query = PFQuery(className: "CardSet")
query.whereKey("user", equalTo: PFUser.currentUser())
query.includeKey("lesson")
query.findObjectsInBackgroundWithBlock({
(objects, error) in
if error != nil {
println(error.localizedDescription)
return
}
for object in objects as? [PFObject] {
var lesson = object["lesson"] as PFObject
println(lesson["name"])
}
})

Parse - Many to One Query

I have a query that gets latest posts by users. Each post has an "Owner" field that has the "ObjectId" of the account that created it. I do this because I want to also display the username of the person who created the post - which is found in the User table.
I looked at the Parse documentation for Queries and came up with this (modeled after one of their examples):
var query = PFQuery(className:"Post")
query.orderByDescending("createdAt");
var innerQuery = PFQuery(className: "User")
innerQuery.whereKey("objectId", matchesQuery: query)
Then I run the findObjectsInBackgroundWithBlock. I don't think I'm getting the information from the User table to get the name of the person who posted the post.
I looked at the object that contains the information for the post but I don't see the information for the user in that object. What am I doing wrong?
Here are screenshots of the headers of my two tables:
POST:
USER:
Thanks!
I think the problem as that you refer to the user table in the query as "PFQuery(className: "User")". But if you use the built in user table, it's name is actually "_User". So use that, or even simplier, use:
var innerQuery = PFUser.query()
Try this
var class = PFQuery(className:"Post")
var finduser:PFQuery = PFUser.query()
finduser.whereKey("objectId", equalTo: class.objectForKey("owner").objectId)
finduser.findObjectsInBackgroundWithBlock{
(objects:[AnyObject]!, error:NSError!)->Void in
if (error == nil){
if let userObjects = objects {
let UserResult = (userObjects as NSArray).lastObject as? PFUser
if let user = UserResult {
println(user.username)
}
}
}
}

Resources