Parse Query where two keys equal one value - ios

I want to perform a query that returns objects of the same value for two different keys. I can do query.selectKeys(keys: [AnyObject]) but I can't specify a value. And I can't do two separate query.whereKey(key, equalTo:) because two constraints act as an AND operator, not OR.
Any way to achieve this, or must I do two separate queries altogether?

It is possible to combine several PFQuery into a single PFQuery based on OR. A simple example can be seen here where I created a new table called ORQueries and filled it with some dummy data. Each object has a foo and a bar property which contain an integer.
func orQueryTheDummyData() {
let fooIsThreeQuery = PFQuery(className: "ORQueries").whereKey("foo", equalTo: 3)
let barIsFiveQuery = PFQuery(className: "ORQueries").whereKey("bar", equalTo: 5)
let combinedQuery = PFQuery.orQueryWithSubqueries([fooIsThreeQuery, barIsFiveQuery])
combinedQuery.findObjectsInBackgroundWithBlock { (result, error) -> Void in
println("result: \(result)")
}
}

Related

How to modify query with .whereKey, but utilizing multiple different parameters in Xcode?

I am creating an application in Xcode, using swift, that is pulling information from a parse-server database (hosted by Heroku). There is a convinient way to modify the query, which can be set up, for example, as follows:
let getFollowedUserQuery = PFQuery(className: "Followers")
getFollowedUserQuery.whereKey("Follower", equalTo: (PFUser.currentUser()?.objectId)!)
However, I would like the query to query based on multiple parameters. Here it is currently only checking one column in the DB. Is there any way to modify this query using .whereKey (or something of the same sort) such that it will check multiple parameters/columns in the DB. Essentially, it will be checking these columns based on search parameters input by the user. But the user can select multiple parameters... so the query needs to return only objects which fit all parameters, not just one. Is there a way to do that?
Did you check the docs? It says:
You can give multiple constraints, and objects will only be in the
results if they match all of the constraints. In other words, it’s
like an AND of constraints.
In your case it would be:
let getFollowedUserQuery = PFQuery(className: "Followers")
getFollowedUserQuery.whereKey("Follower", equalTo: PFUser.currentUser()?.objectId ?? "")
getFollowedUserQuery.whereKey("AnotherKey1", equalTo: anotherObject1)
getFollowedUserQuery.whereKey("AnotherKey2", notEqualTo: anotherObject2)
Another option is to use NSPredicate:
let predicate = NSPredicate(format: "Follower = '\(PFUser.currentUser()?.objectId ?? "")' AND AnotherKey1 = '\(anotherObject1)' AND AnotherKey2 != '\(anotherObject2)'")
let query = PFQuery(className: "Followers", predicate: predicate)

Adding integers in for loop and printing the total

I am looping through integer objects and want to add each integer to an integer variable, then when the for-loop is done, print the total. Is there an easy way to do this? Right now, I can retrieve the objects and print them individually, but the total prints as 0 every time.
Please see the code below. This is for an app written in Swift with Parse as the backend.
Anything helps, and thank you!
var itemsArray = [Int]()
let followingUserItemsQuery = PFUser.query()
followingUserItemsQuery?.whereKey("objectId", equalTo: (PFUser.currentUser()?.objectId!)!)
followingUserItemsQuery?.findObjectsInBackgroundWithBlock({ (objects: [PFObject]?, error) in
if let objects = objects {
for object in objects {
let followingUsersArray = (object["following"] as! [String])
// Get number of listed items of following users with PFUser query for their total objects
for followingUser in followingUsersArray {
print(followingUser)
let query = PFUser.query()
query?.whereKey("objectId", equalTo: followingUser)
//Get each user's listedItems count then append to a higher-level integer variable
query?.getFirstObjectInBackgroundWithBlock({ (object, error) in
itemsArray.append(object!["listedItems"] as! Int)
})
}
}
}
let itemsSum = itemsArray.reduce(0, combine: +)
print(itemsSum)
self.followingUsersAddedItems.text = String("Your followers listed "+String(itemsSum)+" items")
Try this:
var count = 0
...
for followingUser in followingUsersArray {
count += object!["listedItems"] as! Int
}
Your code to reduce / combine the Int values is correct. The problem is that it runs before any of the nested asynchronous Parse queries complete and execute their callbacks. So at the time it runs, itemsArray is still empty. You will need to redesign your code so that itemsSum is calculated only after all the various nested Parse queries have all completed.

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)

PFQueryTableViewController - Getting different objects

I've two Parse tables, Users and Evaluations that are connected by a pointer reference to User.ref (a pointer to itself) -> Evaluations.evaluatedId (a user pointer)
In my PFQueryTableViewController I need to get all users list with their last evaluation. I'm trying with:
override func queryForTable() -> PFQuery
{
let userQuery = PFUser.query()!
let evaluationQuery = PFQuery(className: "Evaluations")
evaluationQuery.whereKey("evaluatorId", matchesKey: "ref", inQuery: userQuery)
let query = PFQuery.orQueryWithSubqueries([userQuery, evaluationQuery])
query.cachePolicy = PFCachePolicy.CacheThenNetwork
return query
}
But I'm getting this error:
'All sub queries of an or query should be on the same class.'
I've searched for a while and I found this:
When using orQueryWithSubqueries, each subquery should be for the same class. If you need to query different classes, you will need either a separate query for each, or use whereKey:matchesQuery: if the other class is pointed to by the parent class.
Any suggestions? Thanks in advance!

PFQuery where array of pointers contains a certain PFObject

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

Resources