CoreData: Query to one-to-many-to-many relationship - ios

I have a core data model like this:
and I'm trying to query all the movies showing a theater with particular schedule.
But I can not figure out how can I this query with NSPredicate.
I tried this:
NSPredicate *moviesPredicate = [NSPredicate predicateWithFormat:#"SUBQUERY (movies, $x, $x.movies.showTimes == %# AND $x.movies.theater.nameOfTheater == %#).#count >0", showTime, theater];
but didn't work. Any of you knows what I'm doing wrong?
I'll really appreciate your help

I'm assuming from your stated objective ("... query all the movies showing a theater with particular schedule") that the entity for your NSFetchRequest is Movies. If so, the attribute and relationship names you use should all be relative to that entity. Hence the theatre name will be given by theaters.nameOfTheater and the show times will be showTimes.showTimes. Because there are many Schedules for a given Movie, your predicate needs to select a movie if ANY of the showTimes.showTimes match your requirement. So one way to write the predicate would be:
NSPredicate *moviesPredicate = [NSPredicate predicateWithFormat:#"theaters.nameOfTheater == %# AND (ANY showTimes.showTimes == %#)", theater, showTime];
Alternatively, the ANY clause can be rewritten as a SUBQUERY:
NSPredicate *moviesPredicate = [NSPredicate predicateWithFormat:#"theaters.nameOfTheater == %# AND SUBQUERY(showTimes, $x, $x.showTimes == %#).#count > 0", theater, showTime];
As a broader recommendation, I would make some changes the names of your attributes and entities; it will help to make things clearer:
Entity names should generally be singular, so Movie not Movies, Theatre not Theatres and Schedule not Schedules.
Likewise the names of relationships should reflect whether they are to-one or to-many. So the Movie entity should have a relationship theatre since it is to-one, and the Schedule entity should have a relationship movies since it is to-many.
Finally, I think you could improve your data model. Currently, each Movie can have only one Theater. In practice, I would imagine that a movie will be shown at more than one theater! Personally, I would have a model like this:
So each Schedule relates to only one Movie and one Theater. But each Theater has many showings, and each Movie has many screenings. Using this model, the predicate to meet your query would be:
NSPredicate *moviesPredicate = [NSPredicate predicateWithFormat:#"SUBQUERY(screenings, $x, $x.theater.nameOfTheater == %# AND $x.showTime == %#).#count > 0", theater, showTime];

Related

Core Data Nested Relationship Fetch Predicate

OK so looked for answers and I'm probably making some assumption that others aren't and thats why the solution is working for them.
Problem:
Lets say I have an Entity called DogOwner. A dog owner can have multiple Dogs and each dog can have multiple Wearables. Note that all relationships are optional and one-to-many (inverse many-to-one).
Aim:
Search all the dog owners that own a dog that has a Wearable type GpsTracker and contains id of 898764.
My approach:
Fetching the entity DogOwner with the following predicate
NSPredicate(format: "(dog.wearable.type == %#) AND (dog.wearable.external_id CONTAINS[cd] %#)", theType, theIdentifier)
I get an unimplemented SQL generation for predicate error.
Tried -> with ANY (Nested core data fetch)
Tried other stuff present on the Internet. Nothing as far I have seen works, I assume that the problem is deeper down given that nested tree structured graph is being successfully queried by others using the dot notation.
While subquery is a feasible way to do this it is exceedingly complicated, and unnecessarily so. Why not simply search for the specific Wearable and get the owner via the convenient to-one relationships?
// fetch wearable with id x
let owner = wearable.dog.owner
I think you need to use SUBQUERY, if only because you need to test both conditions simultaneously:
NSPredicate(format: "SUBQUERY(dog, $d, SUBQUERY($d.wearable, $w, $w.type == %# AND $w.external_id CONTAINS[cd] %#).#count > 0).#count > 0", theType, theIdentifier)
Or "fetch DogOwners having more than 0 dogs having more than 0 wearables matching the criteria".

CoreData Predicate That Compares Two Properties in a Too-Many Relationship

I'm trying to build a predicate that compares two members of a too-many relationship.
The code below more clearly shows my intention, but doesn't seem to work (assume objects is the too-many relationship and has members, member1 and member2):
[NSPredicate predicateWithFormat:
#"(ANY objects.member1 ==[cd] objects.member2)"];
I appreciate any help in determining a properly structured predicate for this type of comparison.
Assuming that you want to fetch the objects which are related to at least one object with
"member1 == member2", you have to use a SUBQUERY:
[NSPredicate predicateWithFormat:#"SUBQUERY(objects, $o, $o.member1 == $o.member2).#count > 0"]
You can find a similar example in the NSExpression Class Reference.

NSPredicate: to-Many relationship with date iOS

I am working on core data relationships and came across one complex situation.
I am having two entities say Customers and Orders.
One customer may order multiple items. So, it's to-Many relationship from customer to order.
Query : Fetch all the customers who haven not ordered since a month.
What's the optimum way to get the result with core data?
Update :
Tried with this predicate :
NSPredicate *newPredicate = [NSPredicate predicateWithFormat:#"ANY custOrders.treatDate <= %#", endDate];
Actually It gives me the result that if customer has ordered a month ago or not..
If it has ordered again then also it returns the result.
I just want the result with customers who haven't ordered since a month.. !!!
Your predicate is incorrect; searching for #"ANY custOrders.treatDate <= %#" will return the customers having ANY orders taking place within the time period provided. What you want to do is find the customer whose maximum order date was less than a month ago.
One of the nifty, lesser known features on Core Data is that you can query using the foundation collection operators like max, min and sum.
This should work:
NSPredicate *p = [NSPredicate predicateWithFormat:#"custOrders.#max.treatDate <= %#", endDate];
Maybe you can use a reversed predicate:
NSPredicate *notFilter = [NSCompoundPredicate notPredicateWithSubpredicate:filter];

"multiple to-many keys not allowed here" issue with a predicate

I need some help with a predicate for a NSFetchedResultsController. My guess is that can be done with a SUBQUERY but I can not figure out how.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Album"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"ANY tracks.playlistItems.playlist == %#", section.playlist];
When executing a fetch request with this predicate I get a “multiple to-many keys not allowed here” error. Which makes sense since album has multiple tracks, and a track has multiple playlist items.
So using natural language here is what I want from this predicate: an album where at least one of its tracks has at least one of its playlistItems that has the following playlist.
Can I achieve this using a SUBQUERY in my predicate?
(I know that this can be easily achieved using 2 fetch requests, but I was wondering if this can be done using one request, since I am using a NSFetchedResultsController)
Yes, you can do this using a SUBQUERY. I have only ever used subqueries a couple of times, but I think yours should look like this:
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(tracks, $t, ANY $t.playlistItems.playlist == %#).#count != 0", section.playlist];

Using NSFetchRequest with complex NSPredicate in a NSFetchRequestController

Im trying to implement something that I'm sure have been implemented a million times before, a search in the core data database, displayed in a table using a fetchRequestController and the searchController.
My problem is writing the NSPredicate for the NSFetchRequest. According to the NSPredicate guide by Apple, not everything you can do in Sqlite is possible with core data.
I have been trying to find a solution for some time, but maybe one of you can use his experience to help me.
CoreData DB description:
Shops has a MANY TO MANY relationship with DiscountProgam.
My use case is as follows: I need to filter out Shops who's name/address/zip/city contains the search string. that's the easy part.
The hard part is creating the section of the database I want to filter from, because I have an array of "active" discountPrograms UID's, and I only want shops that have one of the active discount programs in their "discountPrograms" set. So in pseudo code that would be:
FROM Shops who have at least one discountProgram who's uid IN activeDiscountProgramsArray WHERE name/address/zip/city CONTAINS searchString
Is this possible? am I over reaching the limits of predicates?
If so, how could I do it differently?
Yes, NSPredicate can analyse both the direct attributes of the target entity of a fetch and the attributes of its relationships. Try:
NSArray *validUIDs = ...;
NSString *searchTerm = ...;
[NSPredicate predicateWithFormat:#"(name CONTAINS[cd] %# OR zip CONTAINS[cd] %#) AND (SUBQUERY(discountProgram, $d, $d.UID IN %#).#count > 0)", searchTerm, searchTerm, validUIDs];

Resources