NSPredicate to query many-to-many relationships - ios

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.

Related

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 to return only entities with connected with other entities in one to many relationships

Simple question:
I have an entity group that has to_many relationship with contact entity.
I wish to find only the group entities that their contacts set has at least one contact.
Tried:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY %K != NULL", GroupRelationships.contact];
But no luck.
Thanks
What you want to do it use the count of the relationship:
[NSPredicate predicateWithFormat:#"contacts.#count > 0"];

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 filter based on one to many values

I have 2 entities with a one to many relationship. Category represents my section headers and SubSubCategory represents my rows.
Category
{
name:string
subs<-->>SubCategory
}
SubCategory
{
name:string
numbervalue:NSNumber
}
Currently I can use NSPredicate to filter my sections based on name.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name==%#",#"anamevalue"];
Now I want to further filter this predicate to only return categories that have a Subcategory with a subvalue == 1.
How can I filter the Category entity based on the values in its one to many children?
I tried something like this but its no good.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name==%# AND subs.numbervalue==%#",#"anamevalue",1];
I'll do a predicate like the following:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == %# AND ANY subs.numbervalue == %#)", #"anamevalue", [NSNumber numberWithInt:1]];
The ANY is a predicate modifier that returns true only if there is at least one object in subs collection for which the comparison returns true.
The same result could be done by means of SUBQUERY.
Hope it helps.
The syntax in your predicate is wrong. You are passing an integer value as a string.
Your predicate should be
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name==%# AND subs.numbervalue==%i",#"anamevalue",1]
Other than that it looks correct.

Resources