Filter Between NSDates with NSPredicate - ios

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

Related

Extract objects with specific date from custom object Array

I have an ordered array of Availability object which is a class containing two attributes, startAt and endAt.
I'd like to extract from my availability array the objects from a specific day without taking into account the time.
I'd also like to use NSPredicate instead of "for" loop to do it.
Could you help me?
Thanks
for-in loop actually faster than NSPredicate for me, and easier since u can convert it to string or extract it for easy compare, but if u want then the format should be:
#"(%# >= %#) AND (%# <= %#)", dateForCompare, dayStart, dateForCompare, dayEnd where dayStart is the date to compare at 00:00:00, dayEnd is the date to compare at 23:59:59, tweak it base on your needs, u have to do this because a NSDate object contain exact date and time
Hope it help
if you are using timestamp(NSNumber) to store startAt and endAt then you can use predicate as bellow (to fetch all object whose start date is greter then current date)
NSPredicate *pred = [NSPredicate predicateWithFormat:#"startAt > %#", [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]]];
NSArray *filteredArr = [yourArray filteredArrayUsingPredicate:pred];
and if you are using only date string then you can use
NSPredicate *pred = [NSPredicate predicateWithFormat:#"startAt = %#", #"your date string must be same as formate you saved in array"];
and if you are using only date string then you can use

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

NSPredicate format specifiers issue

I use this predicate:
NSPredicate *offencePredicate =
[NSPredicate predicateWithFormat:#"(%# == %#) AND (%# == %d)", kTeamID, self.selectedTeam.teamID, kPlayerZoneID, ZoneIdTypeOffence];
but the predicate is:
"teamID" == 10 AND "playerZoneID" == 3
instead of:
teamID == 10 AND playerZoneID == 3
How can I trim this "" when I use format specifiers for predicating. And the next question is: is this the right solution using form specifiers in predicate. Because I have some API keys that are correspond to my core data entries attributes. So it is ok to use constant string that will allow quite faster changes if I need to change some of these keys, but is it ok to use this constant for predication?
You need to use %K for the keys.
It would look like this:
[NSPredicate predicateWithFormat:#"(%K == %#) AND (%K == %d)", kTeamID, self.selectedTeam.teamID, kPlayerZoneID, ZoneIdTypeOffence];
Use %K.
See this example from the documentation:
NSString *attributeName = #"firstName";
NSString *attributeValue = #"Adam";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K like %#",
attributeName, attributeValue];
Result:
firstName like "Adam"

Core data subquery predicate

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.

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