PFQuery where array of pointers contains a certain PFObject - ios

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)")
}
}
}
}
}
}

Related

Parse PFQuery bug with geoPoint constraint

I am doing a pretty straightforward PFQuery. I want to get any objects where the specific key I'm entering exists, and the object is within 2 km of user location. However, this query returns all objects within 2 km, but doesn't filter out anything to only return objects where that key exists. I checked and the key ("T(objectIDs[0])") contains the information I think it does. Additionally, I have tried this in a compound query where I am doing a different key in each query. This query works as expected and returns objects within 2 km AND only where the key exists. Have any of you seen behavior like this? Any insight is greatly appreciated, thanks!
let singleQuery = PFQuery(className: locationTagsClassNameConstant)
singleQuery.whereKeyExists("T\(objectIDs[0])")
singleQuery.whereKey(geoPointColumnNameConstant, nearGeoPoint: userGeo, withinKilometers: 2)
singleQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if error == nil {
var dataToExtract:Array<AnyObject> = []
if let objects = objects {
for activity in objects {
dataToExtract.append(activity)
}
complete(result: dataToExtract)
}
} else {
// Log details of the failure
print("Error++++: \(error!)")
}
})

Compare and Match Array Values

When the user searches for a category I need all the arrays that contain that same category to appear + the other categories that are in that respective array.
Once the user has chosen ["Apples", "Oranges", "Limes"] I want to compare which array (out of many) that I queried contains Apples, Oranges or Limes. This can be one array or this can be many arrays.
These are the arrays I'm adding the values to:
var categoryNeeded = [AnyObject]() //The user creates this one and adds values to it
var categoryArr = [AnyObject]() //The Parse arrays are added here:
I have a simple Parse query function.
var query : PFQuery = PFUser.query()!
query.whereKey("contacts", containsString: "\(categoryArr)")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects as [PFObject]! {
for object in objects {
self.categoryArr.append(object["contacts"] as! AnyObject)
print(self.categoryArr)
}
}
}
The 2nd line is suspect:
query.whereKey("contacts", containsString: "\(categoryArr)")
When querying with that line, I get this error (without a crash):
2016-01-23 15:53:47.508 CC[28514:5733236] [Error]: $regex only works
on string fields (Code: 102, Version: 1.11.0)
Without the whereKey line, I get all the values and it prints them. I just can't figure out how to compare and check for matches between the two arrays which ultimately gives the matching arrays. Is there a Swift method that does that?
You should not use containsString but rather containedIn:
query.whereKey("contacts", containedIn: categoryArr)

Parse backend: key won't increment?

I'm trying to increment a number in my parse table under the column "votes". Here's my code:
func upVote() {
var reviewQuery: PFQuery = PFQuery(className: "reviews")
reviewQuery.whereKey("content", equalTo: reviewTextView.text)
reviewQuery.findObjectsInBackgroundWithBlock{
(objects:[AnyObject]!, error:NSError!)->Void in
if error == nil{
for object in objects{
println(object)
let review:PFObject = object as! PFObject
review.incrementKey("votes", byAmount: 1)
}
}
}
}
When I print the object in the console I can see that it is the correct object that I'm looking for. It looks like this:
<reviews:ZqgSVL1Tsd:(null)> {
content = "njk\n";
reviewer = "<PFUser:6387CJtYI1>";
votes = 1;}
But when I look at my parse end, the number of votes has not changed. What am I doing wrong?
Save the object with
review.saveInBackground()
after incrementing the key.
After you modify an object, however small the modification, you must save it after. You are not saving your changes to the object review.
You have several options for saving, including save(), saveInBackground(), saveEventually(), and more. See the documentation for PFObject for more information:
https://www.parse.com/docs/ios/api/Classes/PFObject.html#//api/name/save
For example, you could save the object synchronously with
review.save() and you could save the object asynchronously with review.saveInBackground().

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.

How do I retrieve an array of a custom subclass of PFObjects stored under the PFUser.currentUser()

I'm struggling with retrieving an array of PFObjects that I stored on the PFUser.currentUser()
I have a custom subclass of PFObject: UNUser
Here's how I save the array of [UNUser] called favoriteDrivers:
if let currentUser = PFUser.currentUser() {
currentUser["favoriteDrivers"] = favoriteDrivers
currentUser.saveInBackgroundWithBlock({ (succes: Bool, error: NSError?) -> Void in
if succes {
}
})
}
If I retrieve the entry like this:
if let currentUser = PFUser.currentUser() {
var objects = currentUser["favoriteDrivers"]
println(objects) shows this in the console (the array in this trial has just one entry):
Optional(("<UNUser: 0x174138920, objectId: mEgJALLLA9, localId: (null)> {\n}"))
What is the best way to now fetch the referred to PFObjects and store them in an array of UNUser?
This is what I tried:
var relation = currentUser.relationForKey("favoriteDrivers")
relation.query()!.findObjectsInBackgroundWithBlock{ ( objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
let favoriteDrivers = objects as? [UNUser]
You're setting an array so you need to read an array, not a relation.
Your array is actually an array of pointers, which is exactly what you want, but you do need to ensure that you have all of the data for those pointers as by default (and as you can see in your log) you only get the class type and object ids.
To do that, get the array and then call fetchAllIfNeededInBackground:block: with the array. That will update any of the objects in the array that need it with the current data from the server. This is kind of like your relation query...

Resources