how Use 'AND' 'OR' operation using Parse API in objective-c - ios

I am using parse.com for storing data. I want to retrieve the objects with and & OR conditions using Parse API in objective -c
My Code is :
PFQuery *query = [PFQuery queryWithClassName:#"UserInfo"];
[query whereKey:#"location" nearGeoPoint:_geoPoint withinMiles:5];
[query whereKey:#"Sex" equalTo:[NSString stringWithFormat:#"%#",[[NSUserDefaults standardUserDefaults] valueForKey:SELECTED_LOOKINGFOR]]];

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. For Example to get all players named NOT Michael Yabuti AND aged greater than 18:
[query whereKey:#"playerName" notEqualTo:#"Michael Yabuti"];
[query whereKey:#"playerAge" greaterThan:#18];
// Using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"playerName != 'Michael Yabuti' AND playerAge > 18"];
PFQuery *query = [PFQuery queryWithClassName:#"GameScore" predicate:predicate];
For OR Query, You can use Compound Queries of Parse.e.g. to get all results where wins are greater than 150 or less than 5 you do something like this Like this:
PFQuery *lotsOfWins = [PFQuery queryWithClassName:#"Player"];
[lotsOfWins whereKey:#"wins" greaterThan:[NSNumber numberWithInt:150]];
PFQuery *fewWins = [PFQuery queryWithClassName:#"Player"];
[fewWins whereKey:#"wins" lessThan:[NSNumber numberWithInt:5]];
PFQuery *query = [PFQuery orQueryWithSubqueries:[NSArray arrayWithObjects:fewWins,lotsOfWins,nil]];
[query findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {
// results contains players with lots of wins or only a few wins.
}];
Now as I hope you have understood the concept and mechanism, you may modify your query as per your requirement.

You can do this by using NSPredicate with PFQuery.
See below example
NSPredicate *predicateTeamId = [NSPredicate predicateWithFormat:#"teamid = %#", objSchedule[#"teamid"]];
NSPredicate *predicateOppTeamId = [NSPredicate predicateWithFormat:#"teamid = %#", objSchedule[#"opponentteamid"]];
NSPredicate *predicateBothTeam = [NSCompoundPredicate orPredicateWithSubpredicates:#[predicateTeamId,predicateOppTeamId]];
PFQuery * qryTeam = [PFQuery queryWithClassName:Parse_Class_Teams predicate:predicateBothTeam];
For more details , you can visit this link https://www.parse.com/docs/ios/guide#queries-specifying-constraints-with-nspredicate link.

Related

How to Query in Ascending using Parse

Currently even if I do orderByAscending it never does it by ascending.
What is the issue that I do not see? I am using Parse
PFQuery *foodList = [PFQuery queryWithClassName:#"Food"];
[foodList whereKey:#"date" greaterThanOrEqualTo:minimumDate];
[foodList whereKey:#"date" lessThan:maximumDate];
[foodList orderByAscending:#"expiration_date"];
[foodList findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
}];
Example
food_name expiration_date
Apple 1/2/15
Banana 1/2/15
Pear 1/3/15
Kiwi 1/1/15
Output
The outputs would be very random.
I am assuming that the list is not being sorted while it is querying. I am unsure how to solve this problem though.
I use the NSSortDescriptor variant to do sorting with the Parse SDK and haven't had any issues with that (also filtering on multiple keys like you have is just fine).
This is how you would sort using a descriptor as opposed to a key:
PFQuery *foodList = [PFQuery queryWithClassName:#"Food"];
[foodList whereKey:#"date" greaterThanOrEqualTo:minimumDate];
[foodList whereKey:#"date" lessThan:maximumDate];
NSSortDescriptor *orderBy = [NSSortDescriptor sortDescriptorWithKey:#"expiration_date" ascending:YES];
[foodList orderBySortDescriptor:orderBy];
I've found that the Parse Query is fairly unreliable once you start adding in multiple filters, and it may be a bug, but there doesn't seem to be much reason for it. What I've done, when I have multiple filters, is an NSPredicate.
NSPredicate *minPredicate = [NSPredicate predicateWithFormat:#"date >= %#", minimumDate];
NSPredicate *maxPredicate = [NSPredicate predicateWithFormat:#"date < %#", maximumDate];
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:#[minPredicate,maxPredicate]];
PFQuery *foodList = [PFQuery queryWithClassName:#"Food" predicate:predicate];
[foodList orderByAscending:#"expiration_date"];
[foodList findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
}];
Another possibility is that your query is filtering for date, and then you order by "expiration_date" and I'm not sure if there's a disconnect between the two. Make sure your object nomenclature is what you're wanting.

Parse SubQuery Priority

Say I have two queries in a compound query. Say the potential results exceed the query limit. How does Parse prioritize which query should fill up the result first?
Does it use the first query and fill up as much as possible then move onto the next query until it hits the limit?
PFQuery *lotsOfWins = [PFQuery queryWithClassName:#"Player"];
[lotsOfWins whereKey:#"wins" greaterThan:#150];
PFQuery *fewWins = [PFQuery queryWithClassName:#"Player"];
[fewWins whereKey:#"wins" lessThan:#5];
PFQuery *query = [PFQuery orQueryWithSubqueries:#[fewWins,lotsOfWins]];
[query findObjectsInBackgroundWithBlock:^(NSArray *results, NSError *error) {
}];
So in this case if the table "Player" has 2000 entries and the query limit is 1000 which query has priority? "fewWins" or "lotsOfWins" ?

How to access fields of a pointer's value on parse.com with iOS?

I am designing a database. According to documentation, when number of relationships are greater than 100 and there is extra fields, I must design a Join Table. I designed this Join Table by having two pointer value.
This pointer value is pointing to _User. Later I need only rows for currUser.
This pointer value is the objectId of another table which is an entity. My question is, how can I write a query to return objects for this table in queryfortable.
Let's say:
Table _User
Table Entity
Table Join ---> objectId Pointer1(_User) Pointer2(Event)
This look like this:
This is what I have tried so far:
First I tried in viewDidLoad to get array of invitedUser from cloud and later in queryForTable:
PFQuery *query = [PFQuery queryWithClassName:#"Event"];
[query whereKey:#"objectId" containedIn:_inviteList];
but I need to access _inviteList.objectId which is not possible!
I tried to use innerQuerry or relation query. but as I just started learning parse I am not able to implement this.
PFUser *friendPointer = [PFUser currentUser];
PFQuery *query2 = [PFQuery queryWithClassName:#"Event"];
[query2 whereKey:friendPointer containedIn:_inviteList];
return query2;
This also did not work for me.
PFQuery *innerQuery = [PFQuery queryWithClassName:#"Invite"];
[innerQuery whereKey:#"invitedUser" equalTo:[PFUser currentUser]];
query = [PFQuery queryWithClassName:#"Event"];
[query whereKey:#"user" matchesQuery:innerQuery];
return query;
I appreciate if anyone can help me to write this query or re-design my table in order to have access to this query.
Pleaser try this code and give me review
PFUser *user = [PFUser currentUser];
PFQuery *query = [PFQuery queryWithClassName:#"Invite"];
[query whereKey:#"invitedUser" equalTo:user];
[query includeKey:#"invitedUser"];
[query includeKey:#"eventId"];
[query orderByDescending:#"updatedAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
{
if (error == nil)
{
for (PFObject *underobject in [objects reverseObjectEnumerator])
{
PFUser *user1 = underobject[#"invitedUser"];
NSLog(#"invitedUser is :%#",user1);
}
}
}];

Query Parse containsString make insensitive

I wonder if someone would be able to help. I am trying to search a Parse class for a term using SearchBar. The containsString however is case sensitive and i would like it to be case insensitive. Please see code below;
-(void)filterResults:(NSString *)searchTerm {
[self.searchResults removeAllObjects];
PFQuery *query = [PFQuery queryWithClassName: #"Firefacts"];
[query whereKeyExists:#"Number"];
[query whereKey:#"Number" containsString:searchTerm];
NSArray *results = [query findObjects];
[self.searchResults addObjectsFromArray:results];
}
Any help would be greatly appreciated.
Use Regular Expression (?i) instead ! credit goes to https://stackoverflow.com/a/9655203/2398886 , https://stackoverflow.com/a/9655186/2398886 and http://www.regular-expressions.info/modifiers.html
So replace
[query whereKey:#"Number" containsString:searchTerm];
with
[query whereKey:#"Number" matchesRegex:[NSString stringWithFormat:#"(?i)%#",searchTerm]];
or you can also use
[query whereKey:#"Number" matchesRegex:searchTerm modifiers:#"i"];
Your final code should be :
PFQuery *query = [PFQuery queryWithClassName: #"Firefacts"];
[query whereKeyExists:#"Number"];
[query whereKey:#"Number" matchesRegex:searchTerm modifiers:#"i"];
For Swift use this:
query.whereKey("Number", matchesRegex: searchTerm, modifiers: "i")
reference: https://docs.parseplatform.org/ios/guide/#queries

Combining conditional queries isn't working properly?

I'm needing to use the parse.com method orQueryWithSubquerries: to create a combined conditional query.
Here is my code for it:
PFQuery *testQuery = [PFUser query];
[testQuery whereKey:#"displayName notEqualTo:#"Bob"];
PFQuery *testQuery2 = [PFUser query];
[testQuery whereKey:#"username" notEqualTo:#"frank"];
PFQuery *orQuery = [PFQuery orQueryWithSubqueries:#[testQuery, testQuery2]];
[orQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
PFUser *user = [users firstObject];
}
}];
The code runs fine, but it returns all of my user objects, including the ones that should be filtered out from the 2 queries. Am I using this method wrong, or is there a certain way that I need to use it?
Edit:
I have also attempted to use this method exactly like how this parse.com example does, but it still doesn't work properly.
PFQuery *testQuery = [PFUser query];
[testQuery whereKey:#"numberOfPhotos" greaterThan:#(3)];
PFQuery *testQuery2 = [PFUser query];
[testQuery whereKey:#"numberOfPhotos" lessThan:#(1)];
PFQuery *orQuery = [PFQuery orQueryWithSubqueries:#[testQuery, testQuery2]];
[orQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
// users still contains every user in the app even though it shouldn't according to the parse example
}
}];
You don't need to do a compound query, just query regularly:
PFQuery *userQuery = [PFUser query];
[userQuery whereKey:#"displayName" notEqualTo:#"Bob"];
[userQuery whereKey:#"username" notEqualTo:#"frank"];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
PFUser *user = [users firstObject];
}
}];
You're confusing the use of a compound query, as you have it currently,
TestQuery = All users whose display isn't bob. (includes users whose username is frank)
TestQuery2 = All users whose username isn't frank. (includes users whose display name is Bob)
When you combine them, you get all of the users, your compound is contradictory.
Basically, all of the users left out in query1 are included in query2. And, all the users left out in query2 are included in query1. When you combine these queries, they fill in the missing space and you get all users.
Update
If you're trying to do hasPrefix, it seems like it should work fine:
NSString * prefixToSearch = ...;
PFQuery * displayNameQuery = [PFUser query];
[displayNameQuery whereKey:#"displayName" hasPrefix:prefixToSearch];
PFQuery * usernameQuery = [PFUser query];
[usernameQuery whereKey:#"username" hasPrefix:prefixToSearch];
PFQuery * compoundQuery = [PFQuery orQueryWithSubqueries:#[displayNameQuery, usernameQuery]];
[orQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
NSLog(#"Found %i users", users.count);
}
}];
Update 2 - Let's Test
PFQuery *testQuery = [PFUser query];
[testQuery whereKey:#"numberOfPhotos" greaterThan:#(3)];
PFQuery *testQuery2 = [PFUser query];
[testQuery whereKey:#"numberOfPhotos" lessThan:#(1)];
PFQuery *orQuery = [PFQuery orQueryWithSubqueries:#[testQuery, testQuery2]];
[orQuery findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
// users still contains every user in the app even though it shouldn't according to the parse example
for (PFUser * user in users) {
int numberOfPhotos = [user[#"numberOfPhotos"] intValue];
if (1 <= numberOfPhotos && numberOfPhotos <= 3) {
NSLog(#"Query is failing");
}
}
}
}];
Update 3 - Predicates!
Via our conversation, we got it working with this:
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"keyOne BEGINSWITH 'z' OR keyTwo BEGINSWITH 'a'"];
PFQuery * userQuery = [PFQuery queryWithClassName:#"_User" predicate:predicate];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
NSLog(#"Found objects: %#", objects);
}];
After looking into this once again I ended up changed my solution to being regex based rather than predicate. For my purposes that means I don't need to create an additional lowercase display name property since Parse regex allows for case-insensitive options. Also I can more easily change the parameters of the search with higher levels of flexibility.
My code now looks like this:
// Uses regex to remove white space at the beginning and end of search text
NSString *modifiedSearchText = [Utility stringTrimmedForLeadingAndTrailingWhiteSpacesFromString:self.searchText];
PFQuery *userUsernameQuery = [PFUser query];
// the #"i" modifier is stated in the parse documentation and means case-insensitive
[userUsernameQuery whereKey:#"username" matchesRegex:modifiedSearchText modifiers:#"i"];
PFQuery *userDisplaynameQuery = [PFUser query];
[userDisplaynameQuery whereKey:#"displayName" matchesRegex:modifiedSearchText modifiers:#"i"];
PFQuery *userQuery = [PFQuery orQueryWithSubqueries:#[userUsernameQuery, userDisplaynameQuery]];
[userQuery orderByAscending:#"username"];
return userQuery;
In iOS 8.3, xcode 6.3.1
query.whereKey("name", matchesRegex:searchBar.text, modifiers:"i")
searches upper or lowercase words

Resources