How to Query in Ascending using Parse - ios

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.

Related

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

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.

sort the query depends on the data in an array

In one condition, sort the query depends on the objectId in the array.If the objectId is in the arraym, i want show it top.My code
PFQuery *query = [PFQuery queryWithClassName:#"Group"];
[query orderByDescending:#"pinUser" ]; //Normal Sort
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
------
---------
}
}];
I want to change the change the normal sort to my requirement.
Apply your sorting on resulted objects in block. u can check the objectId of objects in ur arrayM or not on resulted array of objects , not with PFQuery

Load column form parse in to an Array

I am working on a little app with parse.com. I want to download all objects from a column (Array) called "Firstname". I found some code, but when I log "object" it shows the class completely:
PFQuery *query = [PFQuery queryWithClassName:#"Name"];
[query selectKeys:#[#"Firstname"]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
NSLog("%#", objects);
}];
Edit:
PFQuery *query = [PFQuery queryWithClassName:#"Name"];
[query selectKeys:#[#"Firstname"]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
self.FirstnameArray = [objects valueForKey:#"Firstname"];
NSLog(#"%#", self.FirstnameArray);
[self.myTableView reloadData];
}];
A query always returns objects of the class associated with the query. Using selectKeys just limits the data that comes back.
You can extract an array of just the values from the returned array with:
NSArray *values = [objects valueForKey:#"Firstname"]
Thats normal, you will get back the whole object - aka a row from that class you are performing the query on. If I recall correct, SelectKey will return any associated object - ie a relation object. So in your case you do not need to use select.

use subquery in Cloudkit

Anyone knows how to use subquery in CloudKit? Here is my trying code:
// stringArray is String list in Cloudkit
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(stringArray, $fS, ANY $fS = %#).#count != 0", targetString];
CKQuery *query = [[CKQuery alloc] initWithRecordType:#"TestRecord" predicate:predicate];
[publicDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray *results, NSError *error) {
NSLog(#"%#", results);
}];
But caught CKException and showed failed message Expected key-path in comparison expression: SUBQUERY(stringArray, $fS, ANY $fS = "targetString").#count != 0
Any idea or something wrong?
Have a look at the documentation about NSPredicates for CloudKit.
https://developer.apple.com/library/ios/documentation/CloudKit/Reference/CKQuery_class/index.html#//apple_ref/swift/cl/CKQuery
As you can see it only allows a subset of what you can do for the full NSPredicate class. Subqueries and aggregates (like the .#count) are not allowed.

iOS Parse SDK: Multiple query results put into an Array

Scenario = I have an app where users can send each other Messages, Comments, and Pokes that are queried to populate the current user's notificationsTableView. There are 3 queries that must take place, one for Messages, two for Comments, and three for Pokes. The code I'm using is below...
PFQuery *messageQuery = [PFQuery queryWithClassName:#"Message"];
[messageQuery whereKey:#"receiverID" equalTo:[PFUser currentUser][#"userID"]];
[messageQuery orderByDescending:#"createdAt"];
[messageQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
messages = objects;
}];
PFQuery *pokeQuery = [PFQuery queryWithClassName:#"Poke"];
[pokeQuery whereKey:#"receiverID" equalTo:[PFUser currentUser][#"userID"]];
[pokeQuery orderByDescending:#"createdAt"];
[pokeQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
pokes = objects;
}];
PFQuery *commentsQuery = [PFQuery queryWithClassName:#"Comment"];
[commentsQuery whereKey:#"receiverID" equalTo:[PFUser currentUser][#"userID"]];
[commentsQuery orderByDescending:#"createdAt"];
[commentsQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
comments = objects;
}];
What is desired = To consolidate the following arrays: "messages", "pokes", and "comments" into a single array (notificationsArray) that I can sort by "createdAt" and populate my notificationsTableView with notificationsArray objectAtIndexPath:indexPath.row.
Problems I have encountered = (there are two)
(1) When I NSLog the results of any of these queries like so...
PFQuery *messageQuery = [PFQuery queryWithClassName:#"Message"];
[messageQuery whereKey:#"receiverID" equalTo:[PFUser currentUser][#"userID"]];
[messageQuery orderByDescending:#"createdAt"];
[messageQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
messages = objects;
}];
NSLog(#"messages = %#", messages);
It logs "messages = (null)". I can not for the life of me figure out why it is not being set. I know there are messages because when I NSLog the "objects" Array that comes from the query it gives me what I want. It's like the contents of the query will not leave the scope of the query itself. All of the queries above do this. If I can not get the contents of the query out of that block then I can not create an array of all of the arrays to populate the notificationsTableView with, so I'm screwed. Please help.
(2) Even if I do get the results from the queries into individual arrays, I am not sure how to create an array of arrays and order them by a key. Can anyone help me with this? Please.
You are probably looking for the +orQueryWithSubqueries:(NSArray *)queries method, but I don't understand what the return value description is:
a PFQuery that is the or of the passed in PFQueries
I'm thinking this means || (or) ?
You would do it like this:
NSArray *queryArray = [NSArray arrayWithObjects:messageQuery,pokeQuery,commentsQuery,nil];
PFQuery *allQueries = [PFQuery orQueryWithSubqueries:queryArray];
[allQueries findObjects... {
As for the second error, you are right, value is not retained because when the block loses scope all of the local variables inside get destroyed in the autoreleasepool. You need to retain this by using a strong property. self.messages = objects;
(1) You are logging messages outside of the callback function, and the log comes before the callback function returned. Try to log messages into your callback, just after assigning it.
[messageQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
messages = objects;
NSLog(#"messages = %#", messages)
}];
(2) Before sorting, create a NSMutableArray and use the addObjectsFromArray: method with each retrieved array.
To sort notifications, you should use a NSSortDescriptor, which is a mechanism that describes how to sort an array according to the format of contained objects. Here's an example that could match your needs:
NSSortDescriptor *createdAtDescriptor = [[NSSortDescriptor alloc] initWithKey:#"createdAt" ascending:YES];
notificationsArray = [messages sortedArrayUsingDescriptors:#[createdAtDescriptor]];
Hope this help!
EDIT: you can embed your temporary NSMutableArray into an autorelease pool to avoid useless memory leaks, so that the dedicated memory is freed just after you proceed to display.
EDIT: you can use orQueryWithSubqueries Parse method to merge several requests into a single one. It's not annoying in your case cause you're sorting PFObject according to their createdAt key, which is common to every PFObject. In any case, you will have to check PFObject types to display them according to their type. Please see full documentation here. Does not work for queries returning several kind of objects!

Resources