NSPredicate to get entity of a relationship matching two conditions - ios

I am using Core Data to fetch entities. I need to fetch only entities that have a relationship attribute that has the ID of 41 AND that same attribute needs to have the isOn property set to YES.
Here is what I am trying:
[NSPredicate predicateWithFormat:#"(SELF IN %# AND ANY attributes.attributeID.intValue == 41) AND (SELF IN %# AND ALL attributes.isOn == %#)", self.places, self.places, #YES];
For some reason this crashes my app with not explanation.
Any ideas on if my predicate format is wrong?
EDIT:
Doing more research it seems I need to use SUBQUERY but not quite sure how in this case. Here is what I tried but it also crashes with a "cannot parse format" error:
[NSPredicate predicateWithFormat:#"SUBQUERY(SELF IN %#, $e, $e.attributes.attributeID.intValue == %i && $e.attributes.isOn == %#).#count > 0)", self.places, 41, #YES]

Handle the SELF IN outside the subquery, since it relates to the entity being evaluated/fetched, not the related entity, and your SUBQUERY format is also a bit awry:
[NSPredicate predicateWithFormat:#"SELF IN %# AND (SUBQUERY(attributes, $e, $e.attributeID.intValue == %i && $e.isOn == %#).#count > 0)", self.places, 41, #YES]
Also, I'm hoping your relationship name, attributes, is just for demonstration purposes in this question. If not, I would recommend changing it. It's really confusing to have a relationship named attributes: they are mutually exclusive concepts.

Related

NSPredicate to query many-to-many relationships

I have two Core Data classes that are related to each other with many-to-many relation. Let the classes be Item and Group, where Item.groups can reference to multiple Group, and Group.items to multiple Item objects.
I am trying to use NSPredicate to query all Item objects that do not belong to a specific Group. Using [NSPredicate predicateWithFormat:#"ANY group == %#", specificGroup] to query Item objects I can get the inverse set of what I want. It has proven hard to accomplish the opposite.
What I have tried and found not working:
[NSPredicate predicateWithFormat:#"NONE groups == %#", specificGroup] // always returns 0 results
[NSPredicate predicateWithFormat:#"NOT (ANY groups == %#)", specificGroup] // always returns 0 results
[NSPredicate predicateWithFormat:#"ANY groups != %#", specificGroup] // always returns 0 results
Any help much appreciated.

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"];

Inefficient CoreData IN Query

I've got what should be a pretty simple CoreData setup that looks like this:
Track {
NSSet *artists;
NSSet *genres;
}
Artist {
NSSet *tracks;
}
Genre {
NSSet *tracks;
}
So the idea here is, a Track can have multiple Genres and Artists. There is an inverse relationship back to Track in both cases.
I'm trying to get a list of Artists which have at least one Track of a given Genre. I'm using the following predicate: [NSPredicate predicateWithFormat:#"ANY tracks in %#", genre.tracks].
Most of the time this is fast, but sometimes I have a Genre with 10k+ Tracks. This generates a SQL query with 10k+ variables... this takes a long time to run.
I've tried all kinds of things to avoid this including:
[NSPredicate predicateWithFormat:#"ANY %# in tracks", genre.tracks]
[NSPredicate predicateWithFormat:#"SELF IN SUBQUERY(tracks, $t, %# IN $t.genres)", genre]
[NSPredicate predicateWithFormat:#"(SUBQUERY(tracks, $t, %# IN $t.genres).#count > 0)", genre];
And probably some more that I've forgotten. Each of these compiles, but returns no Artist objects.
What can I do to improve upon the efficiency of the IN query I started with (which works)?
You can use
[NSPredicate predicateWithFormat:#"(SUBQUERY(tracks, $t, ANY t.genres = %#).#count > 0)", genre]
which gives the same result as your original predicate, but avoids to build a query with many parameters.

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