I have two tables Photo and Photographer.
Below is the structure of the tables.
I'm trying to fetch the name of all Photographers who have taken a photo called "Panda".
Here's my code but for some reason it's returning empty.
NSArray *matchingPhotographers;
NSFetchRequest *fetch = [[NSFetchRequest alloc]init];
NSEntityDescription *desc = [NSEntityDescription entityForName:#"Photographer" inManagedObjectContext:context];
[fetch setEntity:desc];
[fetch setPredicate:[NSPredicate predicateWithFormat:#"photo.name like[c] %#",#"Panda"]];
NSError *error;
matchingPhotographers = [context executeFetchRequest:fetch error:&error];
NSLog(#"Photographers: %#", matchingPhotographers);
Am I doing something wrong? The query should definitely return at least 1 photographer.
Thanks
Photo is a collection, so your predicated must be:
[fetch setPredicate:[NSPredicate predicateWithFormat:#"ANY photo.name like[c] %#",#"Panda"]];
This predicate finds "Photographers" which have at list one photo (among his photo's collection) with the name like "Panda".
photo is a to-many relationship so it's easier to use a subquery predicate to count the photos in the relationship which match your criteria:
#"SUBQUERY(photo, $p, $p.name ==[c] %#).#count > 0", #"Photo"
Note I'm also not using LIKE so it isn't a regex comparison.
Related
This is what the pertinent part of my object graph looks like:
[Anime] <->> [AnimeName #string #type]
So an Anime object has many AnimeName objects that contain a string and the type of name they are. Now to implement a "Search by Name" feature, I would need a predicate that matches all Anime entities where any name contains the search string. What I have tried so far is this:
NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:#"Anime"];
[fetch setPredicate:[NSPredicate predicateWithFormat:#"names.string == %#", searchString]];
on an NSFetchRequest of Anime entities, this however gives the following error:
"NSInvalidArgumentException", "to-many key not allowed here"
Which makes perfect sense to me, and I could simply work around that by using this:
NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:#"AnimeName"];
[fetch setPredicate:[NSPredicate predicateWithFormat:#"string == %#", searchString]];
and then getting the relationship to the Anime entity from each returned object, but then how do I plug that into an NSFetchedResultsController for my UITableView?
Please help if anyone knows a solution.
For to-many relationships, use "ANY":
NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:#"Anime"];
[fetch setPredicate:[NSPredicate predicateWithFormat:#"ANY names.string == %#", searchString]];
I have two linked types in my CoreData model.
FlightRecording and AHRSMessage
One FlightRecording links to many AHRSMessages.
I've been fetching each recording and iterating through its linked messages:
for (__weak id msgObj in rec.ahrsMessages) {
and have not been seeing the performance I'd like. As I'm fetching the actual recording objects and not the messages I don't believe I can set a batch size on the fetch so I was thinking i'm better off fetching the messages using a correct predicate format.
Assuming I have a NSManagedObjectID for my flight recording is there a quick way to do a predicate query on my AHRSMessage
I've gotten this far which isn't that far:
NSFetchRequest *msgFetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"AHRSMessage" inManagedObjectContext:context];
And then i wasn't sure what to do for my predicate. Do I have to match on an actual field such as:
"ANY flightRecordings = %#" or something like that?
Do I have to reference a specific field in flightRecording or is there a way to just match on the ID?
If "flightRecordings" is a to-many relationship from the AHRSMessage entity to
FlightRecording then this should work:
NSManagedObjectID *flightRecordingId = ...;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"AHRSMessage"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY flightRecordings = %#", flightRecordingId];
[fetchRequest setPredicate:predicate];
The argument of the "ANY flightRecordings = %#" predicate can be a FlightRecording object or a NSManagedObjectID of a FlightRecording object.
in my app i have two entities: Members and Lists. they both have a one-to-many relationships (member can have more than one list, list can have more than one member). now i want to fetch the lists belonging to a specific member. here is my code:
WSAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Lists" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"has_members contains[cd] %#", [self.currentMember valueForKey:#"name"]]];
[fetchRequest setPredicate:predicate];
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
// Handle the error.
NSLog(#"NO LISTS AVAILABLE IN REFRESH");
}
self.currentMember is a managed object of the user himself.
Note: member has name, (NSSet*) member_of_list
list has list_name, has-members
Problem: when i run the code it's breaking at the fetchedObjects array. i suspect that there is something wrong with the NSPredicate but i don't know where and how to fix it. can any one point out the problem?
First, the relationship you describe between Member (Calling an entity in a plural form is confusing) and List is many-to-many.
Second, instead of using CoreData's inherent object graph capabilities, you went and "rolled your own" relationship between the entities (you should use your interface builder to model a CoreData relationship between the two entities).
See HERE how to do that.
after you model your data, your predicate should look something like:
//Not tested
NSPredicate* p = [NSPredicate predicateWithFormat:#"ANY members = %#",self.currentMember];
DO NOT pass a formatted string to create the predicate, use NSPredicate formatting to substitute parameters or you will not be able to accomplish your goal (in most cases).
I'm having a strange problem with Core Data.
The problem is that I'm looking for objects with a property less than X and it isn't returning all the values that matches.
There is no cache and I'm not using //[fetchRequest setFetchBatchSize:50];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"self.level <= [cd] %#", [self.filters objectForKey:#"level"]];
I add it to a MutableArray of predicates and later I execute
NSPredicate *myPredicate = [NSCompoundPredicate andPredicateWithSubpredicates: subPredicates];
This one it's in a function that returns myPredicate called preparePredicates. For the moment there aren't more predicates, only one.
It's NSLog returns: level <=[cd] "30".
I have tried it also with intValue of the string and %i
The main function:
NSError* error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"myEntity"
inManagedObjectContext:self.context];
[fetchRequest setEntity:entity];
NSPredicate* predicate = [self preparePredicates];
[fetchRequest setPredicate:predicate];
//[fetchRequest setFetchBatchSize:50];
NSArray *fetchedObjects = [self.context executeFetchRequest:fetchRequest error:&error];
NSLog (#"Error: %#", error);
NSLog(#"los fetchedobjects: %i",[fetchedObjects count]);
return fetchedObjects;
It doesn't return any error.
If I look at the results there isn't one having a level of 6, but there are others that matches (all are less than the specified). I know there is one with level 6.
If I open the .sqlite in SQLite Database Browser, I can see it there.
If I do with this program a
SELECT * FROM zmyentity WHERE zlevel <30;
it doesn't appear, same as in Core Data do. But if I do a
SELECT * FROM zmyentity WHERE zlevel == 6;
it appears.
I really don't know what is happening. Maybe I'm making a rookie mistake, so please point me in the right direction.
Thank you very much in advance.
Probably you have stored the level as a String attribute, because
"30" < "6"
when comparing strings. Choosing a numeric attribute type (Integer 16/32/64) should solve the problem. The corresponding level property in the myEntity class has then the NSNumber type.
You should also omit the [cd] modifier in the predicate, because that enforces a string comparison.
You predicate could then look like this:
[NSPredicate predicateWithFormat:#"self.level <= %d", [[self.filters objectForKey:#"level"] intValue]]
I'mm working around with Core Data and NSFetchedResultsController.
My Data Model looks like this:
Product with one-to-many relationship called dataLines.
The dataLine entity has a property name theWeek.
I want to fetch all Product where dataLines.theWeek == someValue. This is easily done with a subquery. But this returns all dataLines. Is it possible to create a NSPredicate that returns the Product and a subset if dataLines only with the dataLines == someValue?
What you want to achieve could be reached in two ways:
using a SUBQUERY
[NSPredicate predicateWithFormat:#"SUBQUERY(dataLines, $x, $x.theWeek == %#).#count > 0)", [NSNumber numberWithInt:18]];
or the ANY modifier
[NSPredicate predicateWithFormat:#"ANY dataLines.theWeek == %#", [NSNumber numberWithInt:18]];
You can do also the following if you need to check against multiple values:
[NSPredicate predicateWithFormat:#"SUBQUERY(dataLines, $x, $x.theWeek == %# or $x.theWeek == %#).#count > 0)", [NSNumber numberWithInt:18], [NSNumber numberWithInt:19]];
The same can be applied to ANY modifier. ANY ... OR ANY ....
Maybe if you share some code we could help you.
P.S. I suppose you don't use scalar values and theWeek is a number.
Hope it helps.
You should fetch the dataLine property instead.
Assuming your Product and dataLine entity connected by relationship someRelation then you can try this code;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityWithName:#"dataLine" inManagedObjectContext:self.managedObjectContext]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"dataLines.week == %#",theWeek]];
NSMutableArray *tmpProduct [[NSMutableArray init] alloc];
NSMutableArray *tmpArray = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (dataLine *theDataLine in tmpArray);
NSLog(#"%#",theDataLine.someRelation.name);
tmpProduct = theDataLine.someRelation.name;
then you can just call tmpProduct to call or display your product in table view
Create a fetch request for the 'Product' entity:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity: [NSEntityDescription entityForName:#"Product" ...]]
then create a predicate using the properties/attributes of Product with 'ANY':
[fetchRequest setPredicate:
[NSPredicate predicateWithFormat:#"ANY dataLines.theWeek == %#", <whatever week>]];
then execute the fetch to get an array of Product with at least one <whatever week>.
Generally see 'Fetching Managed Objects', NSPredicate and related documentation.