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.
Related
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.
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)
}
}
}
Objects in my class Deal have an attribute relatedContacts which is an array of pointers to Contact objects. I'm running the following query to determine whether the current Contact object is the target of a pointer in any Deal, prior to deleting the Contact.
let relatedContactObjects:NSArray = [self.contactObject] as NSArray
let relatedContactQuery:PFQuery = PFQuery(className: "Deal")
relatedContactQuery.fromLocalDatastore()
relatedContactQuery.fromPinWithName("Deals")
relatedContactQuery.whereKey("user", equalTo: PFUser.currentUser()!)
relatedContactQuery.whereKey("relatedContacts", containsAllObjectsInArray: relatedContactObjects as [AnyObject])
However this returns Parse Error 102: "Value type not supported for $all queries."
The Parse documentation says that containsAllObjectsInArray takes an NSArray, but Xcode shows a warning that NSArray is not implicity convertible to [AnyObject].
Any ideas how I can make this query work?
Edit: I looked at the contents of relatedContacts and it seems that each instance contains an array of dictionaries, example: [{"__type":"Pointer","className":"Contact","objectId":"BoLym053hX"},{"__type":"Pointer","className":"Contact","objectId":"AgpnxAFUBn"},{"__type":"Pointer","className":"Contact","objectId":"ob20tThdfp"}]
As suggested, I've also looked at the containedIn query constraint, but that is used to identify objects that are contained in a given array. I am trying to identify arrays that contain a given object.
Parse.com overloads equalTo: by allowing it to mean either: (a) a singular property equals the operand, or (b) an array property contains the operand. So you're objective is easily stated as follows:
relatedContactQuery.fromPinWithName("Deals")
relatedContactQuery.whereKey("user", equalTo: PFUser.currentUser()!)
relatedContactQuery.whereKey("relatedContacts", equalTo:self.contactObject)
Prior to the accepted answer, I also tried using loops to go through the arrays and identify whether they contained the current object, then incremented a count.
var dealsPointingToContactCount:Int = 0
func countDealsRelatedToContact() {
let dealsWithRelatedContactQuery:PFQuery = PFQuery(className: "Deal")
dealsWithRelatedContactQuery.fromLocalDatastore()
dealsWithRelatedContactQuery.fromPinWithName("Deals")
dealsWithRelatedContactQuery.whereKey("user", equalTo:PFUser.currentUser()!)
dealsWithRelatedContactQuery.whereKeyExists("relatedContacts")
dealsWithRelatedContactQuery.findObjectsInBackgroundWithBlock{(objects, error) -> Void in
if (error == nil) {
var dealsWithPointersToContacts:NSArray = objects! as NSArray
for deal in dealsWithPointersToContacts {
var dealContactsArray:NSArray = deal["relatedContacts"] as! [PFObject]
for contact in dealContactsArray {
if contact as! PFObject == self.object {
self.dealsPointingToContactCount++
println("Deals pointing to current contact: \(self.dealsPointingToContactCount)")
}
}
}
}
}
}
I need get an objectId from a user that is not the current user. I'm able to do a PFUserQuery to get the user that I'm looking for. I can see all the data there, I just can't extract the objectId.
var query = PFUser.query()
query!.whereKey("email", equalTo:userNameObject)
query!.findObjectsInBackgroundWithBlock {
(newUser: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
println(newUser) //This gets the correct User Record
var userVariable = newUser.objectId as String //Error: Type of expression is ambiguous without more context
Thanks!
In the above code, newUser is an array, not a PFUser object. If you're guaranteed to only get 0 or 1 user from your query, then you should use getFirstObjectInBackground rather than findObjectsinBackground.
Try the following:
var query = PFUser.query()!
query.whereKey("email", equalTo:userNameObject)
query.getFirstObjectInBackground { newUser, error in
if error == nil {
println(newUser)
var userVariable = newUser.objectId as String
}
}
I'm trying to access the "objectId" field in "User" table, while running a query on a "Photos" table.
Here is the Parse.com query (simplified) run on "Photos" table:
func checkDbForNewPhotos() {
var query = PFQuery(className:"Photos")
query.whereKey("fbId", equalTo:"34343434343434")
query.includeKey("user.objectId"); // Is this what is needed to access user info ?
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
for object in objects {
println(object) // See sample object below
println(user.objectId) // Error here: user type doesn't have member objectId
}
println(object): Here is a sample object returned from the query. I'm trying to access 9wEGRWSnTk from the "user" field which is a pointer to another table.
<Photos: 0x7c091fd0, objectId: 6D0aHreHsC, localId: (null)> {
alerts = 0;
country1 = france;
country2 = "";
imageFile = "<PFFile: 0x7b7d9130>";
user = "<PFUser: 0x7b7d95f0, objectId: 9wEGRWSnTk>";
}
How should I format that in swift to access 9wEGRWSnTk ?
I had the same problem. You need to cast it to a PFUser and then access the information.
let pfObject:PFObject = object as PFObject
let userObject:PFUser = pfObject["user"] as PFUser
print("User \(userObject.objectId)")
You should use
println(object["user"].objectId)
if the column where you store your user named as "user".
You could also just say EqualTo and use the PFUser.currentuser()
that way you load everything from that user only
else try to explain why you need the objectId when querying
query.whereKey("user", equalTo: PFUser.currentUser())