NSPredicate: to-Many relationship with date iOS - 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];

Related

Is there a way to setup NSPredicate based on actual value stored in CoreData?

I need to set up my NSPredicate base on actual value stored in CoreDate.
Assuming we have a CoreData entity: "Graduate". we want to fetch graduate whose graduation date is earlier than Date1 if his/her graduation date is not null. Otherwise, I want to check if his/her birthday is earlier than Date2.
The predicate would look like this:
"if graduationDate != null graduationDate < %# else birthday < %#"
So I actually have two predicate. The second one should only come into effect if the field which first predicate wants to check is null.
My thoughts:
I can process this in my APP instead of CoreData, but just wonder is there a way to use only one NSPredicate to sort it out.
Some posts mentioned that NSPredicate is an equivalent to SQL Where Clause, which makes sense to me. And I think what I need here is going to beyond what Where Clause is capable of.
My question is not about how to filter fetch result using NSPredicate. It's about how to setup NSpredicate using a flow control like if else clause
You can use NSCompoundPredicate to combine smaller predicates.
let graduates = NSPredicate.init(format: "graduationDate != NULL AND graduationDate < %# ", graduationDate);
let oldPeople = NSPredicate.init(format: "graduationDate == NULL AND birthday > %# ", cutOffBirthday);
let predicate = NSCompoundPredicate.init(orPredicateWithSubpredicates: [graduates, oldPeople]);

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

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

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.

"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