Core data subquery predicate - ios

I'm trying to get a subquery predicate to work and I'm struggling.
I have two entities.
[League] <---->> [Game]
Game has a property kickOffDate.
I'd like to use a predicate to return all Leagues that have at least one Game with a kickOffDate today.
I am using this predicate...
// startOfDay and endOfDay are functions to return the given date with 00:00:00 and 23:59:59 respectively
NSPredicate *startOfDayPredicate = [NSPredicate predicateWithFormat:#"SUBQUERY(games, $g, $g.kickOffDate >= %#).#count > 0", [self startOfDay:[NSDate date]]];
NSPredicate *endOfDayPredicate = [NSPredicate predicateWithFormat:#"SUBQUERY(games, $g, $g.kickOffDate <= %#).#count > 0", [self endOfDay:[NSDate date]]];
NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:#[startOfDayPredicate, endOfDayPredicate]];
However, when I use this I don't seem to get any results.
Have I written the predicate correctly?
Is there a better way of doing this?

Have you tried (untested):
[NSPredicate predicateWithFormat:#"SUBQUERY(games, $g, $g.kickOffDate >= %# AND $g.kickOffDate <= %#).#count > 0", [self startOfDay:[NSDate date]],[self endOfDay:[NSDate date]]];
== League that have a game with a kick-off date in a given range
Your solution is equivalent to:
[NSPredicate predicateWithFormat:#"ANY games.kickOffDate >= %# AND ANY games.kickOffDate <= %#",start,end];
== League that have a game that start after a given date and have a game that start before a given date (could be different games, or the same game)
Which should return more results than you like.
Edit:
As #Martin R suggested, you should verify that your data does indeed include a League answering the predicate to test it.
If you still get no results, check to see if there were errors during execution of the request and your data-stack is properly initialized.

Related

Filter Between NSDates with NSPredicate

A simplified version of my coredata model looks like this
I'm trying to filter a set of assets that meet the following criteria "type"== "DIVIDEND_TYPE" and the "date" falls between "startDate" and "endDate".
My predicate looks like this
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:
#"ANY transactions.type == %# AND ANY transactions.date >= %# AND ANY transactions.date <= %#", DIVIDEND_TYPE, startDate, endDate];
NSSet *filteredSet = [self.portfolio.assets filteredSetUsingPredicate:myPredicate];
This predicate seems to respect the startDate and type, but not the endDate. The filteredSet always includes assets that contain transactions that have dates beyond the endDate.
What I'm I doing wrong?
The conditions get tested independently for each ANY clause, so if an Asset has any transactions of the right type, and any transactions with date after startDate ,etc, - but it could be a different transaction that meets each test. Use SUBQUERY instead: it allows you to test several attributes of each transaction:
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:#"SUBQUERY(transactions, $T, $T.type == %# AND $T.date >= %# AND $T.date <= %#).#count > 0", DIVIDEND_TYPE, startDate, endDate];

Filtering NSArray of NSmanagedObject with one-to-may relationship

I have 3 entities, "Bar", "Waiter", "Product" the relationship is as follows,
A "Bar" has one to many relationship with "Waiter" and the same from Waiter to Product.
I have an array of Waiters working on a Bar, and I want to filter the waiters based on if they served a certain Product.
Im trying to filter the array of all the Waiters in a bar, [bar.toWaiter allObjects]
So far I've tried:
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:#"toProduct.endSaleDate > %# AND toProduct.published == YES", [NSDate date]];
and
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:#"ANY toProduct.endSaleDate > %# AND ANY toProduct.published == YES", [NSDate date]];
I only want those waiters who have a Product that has "published" to YES and endSaleDate in the future. What Im getting is Waiters that have either a Product published or a product with a future date.
How can I achieve what Im looking for.
Thanks!
It seems that the predicate is interpreted as "give me waiters which have ANY published product and ANY product with a future date". But it does not require that the same product fulfils both conditions.
You can use a SUBQUERY to ensure that:
[NSPredicate predicateWithFormat:"#"SUBQUERY(toProduct, $product, $product.published == 1 AND $product.endSaleDate > %#).#count > 0"];

Data Retrieval With three entities without using manual looping

I have three entities.
I need to retrieve all the lectures that teach a certain student.
So far the solution i was able to come up is
first to use a subquery to retrieve all the courses the student takes by
NSPredicate *predicate = [NSPredicate
predicateWithFormat:#"SUBQUERY(students, $student, $ student.name ==
'student two').#count > 0"];
I execute the fetched request to obtain fetchedObjects.
Next i compare all the lecture objects with fetchedObjects. The lecture who conducts a course in fetchedObjects is the person who teaches the student in question.
Is there a much neater method of doing this without doing a comparison by hand ?
I mean can i do it using predicates alone?
To fetch all lecturers that have a course with the given student, use the predicate
[NSPredicate predicateWithFormat:#"SUBQUERY(courses, $c, ANY $c.students.name == %#).#count > 0", studentName]
Remark: In your first example (fetch all courses for a student), you don't need a SUBQUERY:
[NSPredicate predicateWithFormat:#"ANY students.name == %#", studentName]
Do you want to retrieve "Course" entity or "Lecturer" entities ?
for Course you could try this predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"students.name = %#",NAME];
now you have Course entities and you can get Lecturers too,
for Lecturers you could try
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY courses.#unionOfArrays.students.name = %#",NAME];

NSPredicate for a Core Data Search

I have 3 NSManagedObjets; Person, Stuff, and Collection.
I want to use a NSPredicate to get a list of all Collections that ThePerson has.
Example: Scott has objectA and objectB which are in collection Letters and object1 which is in collection Numbers.
I want to be able to do a fetch request and get back collection Letters and Numbers.
I tried:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY stuffs.persons == %#", person];
And:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(stuffs, $s, ANY $s.persons == %#)", scott];
Any suggestions?
Your SUBQUERY syntax is wrong (for a full explanation, see this answer or this answer). It should be something like:
SUBQUERY(stuffs, $s, ANY $s.persons == %#).#count > 0
Since it seems that you already have a reference to a ThePerson object, you don't need to do a fetch or use a predicate. You can traverse the relationships you've declared to get the collections. You can get all of the Collections that ThePerson has by using:
NSSet *collections = [person valueForKeyPath:#"stuffs.collections"];

NSPredicate Aggregate Operations with NONE

How do I create a predicate that can fetch: all questions does not contain answer.correct = "1".
The following predicate doesn't work if the returned array contain "0" and "1":
[NSPredicate predicateWithFormat:#"NONE answers.correct IN %#", [NSArray arrayWithObject:#"1"]];
Also tried with NOT (ANY ...) : same result
Is this a Bug?
Short answer: To get all objects that do not have any "answer" with "correct == 1", use the following SUBQUERY:
[NSPredicate predicateWithFormat:#"SUBQUERY(answers, $a, $a.correct == 1).#count == 0"]
Explanation: Both predicates
[NSPredicate predicateWithFormat:#"NONE answers.correct == 1"]
[NSPredicate predicateWithFormat:#"NOT (ANY answers.correct == 1)"]
should work (as I understand the NOT and ANY keywords) but they don't.
They return the same result set as
[NSPredicate predicateWithFormat:#"ANY answers.correct != 1"]
as can be seen by setting the launch argument -com.apple.CoreData.SQLDebug 3 and inspecting the SQL select statements.
This seems like a Core Data bug to me. Using the SUBQUERY is a workaround for that problem.

Resources