ios 5 setPropertiesToFetch ...is not in the GROUP BY issue - core-data

i'm using nsexpression to group and count on multiple attributes. the fetch result works fine under ios 6 and ios 7, but it doesnt work under ios 5.
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'SELECT clauses in queries with GROUP BY components can only contain properties named in the GROUP BY or aggregate functions (startDateTime is not in the GROUP BY)'
* First throw call stack:
(0x3689022 0x309bcd6 0x13357d9 0x133543e 0x13351f0 0x1334fc3 0x1334619 0x13340b0 0x133345d 0x13312fd 0x138432b 0x13841fc 0x1384051 0x3285951 0x3285e00 0x1383ff5 0x1383e6d 0x13312fd 0x144043f 0x3a55f 0x38fea 0x22c5a1e 0x2430323 0x3a796 0xc961 0x1b01c6 0xc572 0xc42a 0x1b0684 0x215b34 0x19dff2 0x215a8d 0x1b05cd 0xc142 0xf5c5 0x1b0684 0x215b34 0x19dff2 0x215a8d 0x1b05cd 0xd722 0x384b 0x21fc386 0x21fd274 0x220c183 0x220cc38 0x2200634 0x5177ef5 0x365d195 0x35c1ff2 0x35c08da 0x35bfd84 0x35bfc9b 0x21fcc65 0x21fe626 0x29ad 0x2915 0x1)
terminate called throwing an exception
and the code is as follow:
NSPropertyDescription *propDesc = [properties objectForKey:#"partyId"];
NSExpression *partyid = [NSExpression expressionForKeyPath:#"partyId"];
NSExpression *partyIdCount = [NSExpression expressionForFunction:#"count:" arguments:[NSArray arrayWithObject:partyid]];
NSExpressionDescription *countPartyId = [[NSExpressionDescription alloc] init];
[countPartyId setExpression:partyIdCount];
[countPartyId setExpressionResultType:NSInteger64AttributeType];
[countPartyId setName:#"countResultPartyId"];
NSExpression *startDateTime = [NSExpression expressionForKeyPath:#"startDateTime"];
NSExpression *latestDateTime = [NSExpression expressionForFunction:#"max:" arguments:[NSArray arrayWithObject:startDateTime]];
NSExpressionDescription *dateTimePropertyDescription = [[NSExpressionDescription alloc] init];
[callDateTimePropertyDescription setExpression:latestDateTime];
[callDateTimePropertyDescription setExpressionResultType:NSDateAttributeType];
[callDateTimePropertyDescription setName:#"latestDateTime"];
NSPropertyDescription *sortDateGroup = [properties objectForKey:#"sortDate"];
NSPropertyDescription *userId = [properties objectForKey:#"userId"];
[fetchRequest setPropertiesToGroupBy:[NSArray arrayWithObjects:propDesc,sortDateGroup,userId, nil]];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:propDesc,dateTimePropertyDescription, sortDateGroup,userId,countPartyId, nil]];
[fetchRequest setResultType:NSDictionaryResultType];
it looks like it wants me to groupy by time startDateTime too. but grouping wont work because there could be multiple startDateTime and i need the latest "max" time from it. surprisingly, it works under ios 6 & 7- does anyobe know how to accomplish that? thank you.

the expressionForFunction:#"max:" or expressionForFunction:#"min:" doenst work on ios 5. i had to leave it out of the query. and did a second query to get max nsdate for ios 5.

Related

Fetching counts of to-many Core Data relationships with NSExpression

My Core Data model has a Note entity with a to-many relationship to a Link entity, accessed through a links property on Note.
I'm trying to fetch the count of the links property for each note in Core Data. To do so, I followed the example at the link below, but I'm getting an unexpected result.
Chained expressions to perform calculations in Core Data
Here's how I'm configuring the fetch request and related expression descriptions:
// Create the expression description that should return the link count for each note.
NSExpression *linksExpression = [NSExpression expressionForKeyPath:#"links"];
NSExpression *countExpression = [NSExpression expressionForFunction:#"count:" arguments:#[linksExpression]];
NSExpressionDescription *linkCountExpressionDescription = [[NSExpressionDescription alloc] init];
linkCountExpressionDescription.name = #"linkCount";
linkCountExpressionDescription.expression = countExpression;
linkCountExpressionDescription.expressionResultType = NSInteger32AttributeType;
// Execute a fetch request that should return an array of dictionaries, each with a single "linkCount" key.
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Note"];
fetchRequest.resultType = NSDictionaryResultType;
fetchRequest.propertiesToFetch = #[linkCountExpressionDescription];
NSArray *countsArray = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
The SQLite store I'm working with contains 1000 notes, so I expect to get an array of 1000 dictionaries, each containing a LinkCount key and the count of its links relationship. Instead, I get a single dictionary that gives me the total count of all links.
What should I do differently to get the link counts for each note?

iOS - NSPredicate string.length always evaluates to 0 when string starts with arithmetic operators + - * /

I have a simple method that uses NSPredicate to return the number of rows where comments.length > 0.
Problem is, I found that when the Comment column starts with + - * or /, the length property always evaluates to 0, and thus the row is excluded from the count.
I opened the table in SQLite browser and verified the column is a VARCHAR. Using a SQLite query to check string length works just fine (LENGTH(ZComments) > 0), so this must be a CoreData issue.
Here is my function...
-(int)getCommentsCount{
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setIncludesSubentities:YES];
[request setEntity:[NSEntityDescription entityForName:#"InspectionRecord" inManagedObjectContext:managedObjectContext]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(comments.length > 0)"];
[request setPredicate:predicate];
NSError *err;
NSUInteger count = [managedObjectContext countForFetchRequest:request error:&err];
//count is ALWAYS 0 if 'comments' starts with + - * or / WHYYY???
return count;
}
I was able to work around this by checking for empty/null string instead of using .length, but I'd really like to know why .length fails when the string starts with certain characters.
Has this happened to anyone?
You cannot use Objective-C functions like length in a Core Data fetch request
(and the ".length" part is simply ignored when Core Data translates the fetch request
to a SQLite query). But you can simply compare with an empty string instead:
[NSPredicate predicateWithFormat:#"comment != ''"]
For other queries involving the length, you can use the MATCHES operator with
a regular expression as shown here: CoreData predicate: string property length?.

Split NSString into multiple entries to NSMutableDictionary as key/value?

Ok, so I have this problem I have been spinning my head around for some time now.
I have a NSString like the following:
NSString* foo = #"Brand: [Ford], Model: [Focus], Color: [black]";
which I would like to transfer into a NSMutableDictionary with Brand, Model, Color as keys and Ford, Focus, black as values (without the brackets [] ), but cannot seem to find any solution to this. How do I come about accomplishing the given scenario?
Edit:
Right now I use
NSArray *stringComponents = [foo componentsSeparatedByString#","];
which gives me an array like
stringComponents = [#"Brand: [Ford]",
#"Model: [Focus]",
#"Color: [black]",];
that I need to get into the syntax proposed by Sam, but how?
NSDictionary is basically just an array that stores the values of the objects and keys, so you'd do something such as:
NSArray *keys = [NSArray arrayWithObjects:#"Brand", #"Model", #"Color", nil];
NSArray *objects = [NSArray arrayWithObjects:#"Ford", #"Focus", #"black", nil];
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects
forKeys:keys];

CoreData: NSPredicate based on relationships

I'm working on a recipe book right now using Core Data. It's the first time I'm using CoreData and it's working so far, but I'm having some trouble using it in the iPad's split view.
Here's my object model:
http://i621.photobucket.com/albums/tt295/Naosu_FFXI/ObjectModel.png
In my app, steps and ingredients are shown in two tables in the detail view. When I have one recipe, it works as expected. However, the NSFetchedResultsControllers for both tables pulls all the information regardless of what recipe you select. So using an NSPredicate seems to be the most obvious choice.
Here is my code snippet for the NSPredicate:
filteredIngredientsArray = [[NSMutableArray alloc] init];
.... snip ....
//---------- Filtering the ingredients by name ----------
NSError *error = nil;
NSPredicate *ingredientsPredicate = [NSPredicate predicateWithFormat:#"recipe.recipeName == '%#'", selectedName];
[fetchRequest setPredicate:ingredientsPredicate];
NSLog(#"Filtering the INGREDIENTS with this: %#", selectedName);
NSArray *loadedIngredients = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
filteredIngredientsArray = [[NSMutableArray alloc] initWithArray:loadedIngredients];
[self.ingredientTable reloadData];
When I use this, my tables don't get filled period.... so it's definitively working, but not working as I want it to. My NSLog shows that the value of the selectedName variable is the name of the recipe the user taps on.
This has been driving me up the wall and it really bothers me, so any feedback/help would be appreciated.
Remove the single quotes around %# in the predicate format:
[NSPredicate predicateWithFormat:#"recipe.recipeName == %#", selectedName]

NSPredicate on nested object / NSSet to filter the result during NSFetchRequest

I want a simple predicate that returns me all the groups which have mode = 0 and the mode of the enrollments in the group = 0
To be precise i need a predicate to access the nested object properties.
Somehow a predicate like:
[NSPredicate predicateWithFormat:#"mode = 0 AND enrollments.Enrollment.mode = 0"]
the above predicate is wrong and obviously doesn't work.
EDITED:
I have given a go to the following predicate too but been unsuccessful.
[NSPredicate predicateWithFormat:#"mode = 0 AND ALL ( SUBQUERY(enrollments,$varEnrollment,$varEnrollment.mode = 0))"]
I need result which contains all groups that are active (group.mode = 0) AND with all enrollee's that are active (enrolles.mode = 0)
but for me this predicate doesn't work.
From your question and the comments I guess that you want
[NSPredicate predicateWithFormat:#"mode = 0 AND (ALL enrollments.mode = 0)"]
UPDATE
It seems that the ALL aggregate does not work. It throws
'NSInvalidArgumentException', reason: 'Unsupported predicate (null)'
as #yunas noticed. This has also been noticed previously, e.g.
Core Data, NSPredicate and to-many key
Crash using Aggregate Operation: "ALL" in a Core Data iOS Application
On the other hand, the ANY aggregate works just fine. So as a WORKAROUND, one can replace ALL with an equivalent ANY expression:
[NSPredicate predicateWithFormat:#"mode = 0 AND NOT(ANY enrollments.mode != 0)"];
And this actually works (I have tested it)!
UPDATE 2
During the discussion it has become clear that yunas wants to display a table with one row for each group with mode=0, and within the table row display all enrollments of that group with mode=0.
First solution (probably the better one): Find all admissible groups first with the method given above. For each row (in cellForRowAtIndexPath:) filter the enrollments for that group and draw the cell.
Second solution: Fetch all enrollments and sort them by group. This requires only one fetch request, but the result is not so suitable as table view data source. The fetch request would look like this:
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Enrollment"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"mode = 0 AND group.mode = 0"];
request.predicate = predicate;
NSSortDescriptor *sort1 = [NSSortDescriptor sortDescriptorWithKey:#"group.name" ascending:YES];
NSSortDescriptor *sort2 = [NSSortDescriptor sortDescriptorWithKey:#"share" ascending:YES];
request.sortDescriptors = [NSArray arrayWithObjects:sort1, sort2, nil];

Resources