Accessing objects using NSPredicate from Core Data - ios

I tried to find answer to my simple question with no luck... I'm working on CoreData and i have two entities lets take an example of "Photo and Photographer" one to many relationship, means one photographer can have multiple photos... Now i did store objects using
[NSEntityDescription insertNewObjectForEntityForName...]
I'm having issues retrieving "all photos" from a specific photographer. I'm using this code
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Photographer"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"name = %#",#"photographerName"];
fetchRequest.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"timeStamp" ascending:YES]];
this code is returning photographer however i only need ALL photos taken by this photographer.
I'm new to CoreData, i'm not sure if i should be using "Photos" entity?
thanks in advance.

Your fetch request should request Photo entity.
Then, in your predicate, you can specify the name of the photographer like so:
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"photographer.name = %#",#"photographerName"];
Or better yet, it would be much faster to first get the photographer object, and then test the relationship in the predicate:
Photographer* photographer = ... //Get required photographer here
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"photographer = %#", photographer];

Use this to sort the photographer.photos array.
NSSortDescriptor *sortKey = [[NSSortDescriptor alloc] initWithKey:#"timestamp" ascending:YES];
NSArray *sorters = [NSArray arrayWithObject:sortKey];
NSArray *sortedArray = [photographer.photos sortedArrayUsingDescriptors:sorters];

Related

NSFetchedResultsController - grouping results from a single entity

Let's say that my Core Data model contains the following entity, Family:
I'd like to use NSFetchedResultsController to display the contents of the Family in a UITableViewController in the following format where parents are "sections" with children listed under a "parent":
In my view controller file, I have the following:
- (void)setFRC
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:[Family entityName]];
NSSortDescriptor *sort1 = [[NSSortDescriptor alloc] initWithKey:#"Child" ascending:YES];
NSSortDescriptor *sort2 = [[NSSortDescriptor alloc] initWithKey:#"Name" ascending:YES];
NSArray *sorters = [NSArray arrayWithObjects:sort1, sort2, nil];
[request setSortDescriptors:sorters];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:[MYCoreDataManager managedObjectContext] sectionNameKeyPath:#"Child" cacheName:nil];
}
When using the code above, however, I'm getting the following table instead:
Can somebody tell me how to get the "children" grouped underneath the proper "parent"? I realize that the data model could be separated such that there are separate entities for child and parent; however, I'm working with legacy code and don't have the luxury of modifying the data model for the time being.
I think you need to use predicates:
Get all Parents
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"Child == %#", #NO];
Loop through the parents and get all their Children
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"Child == %# AND Parent == %#", #YES, parent.Name];
This solution results in an array construct. Not sure, this answer is helping you, since you're looking for a NSFetchedResultsController.

Core Data Sorted relationship + NSFetchedResultsController

I have a model with Tags and Documents. Each Tag can have multiple Documents. Each document can have multiple Tags. In a Tag all the Documents are ordered. The Tag.Documents relationship is currently an NSSet, so it's unordered.
I am also using a NSFetchedResultsController with a NSSortDescriptor that just returns the Documents in other of their creation-time property. But I need them to be in a different order depending on the Tag I'm currently displaying.
Having looked at multiple other SO questions it seems that using a NSOrderedSet might not offer the solution, so instead I am trying to add a third object TagDocumentPair that points to 1 Tag and 1 Document. Each tag and document will point to multiple TagDocumentPair objects. Pretty straight forward.
The question I have is how should I create the NSSortDescriptor?
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"Document" inManagedObjectContext:.managedObjectContext];
request.predicate = [NSPredicate predicateWithFormat:#"tags contains %#",tag];
request.fetchBatchSize = 20;
request.sortDescriptors =
// #[[NSSortDescriptor sortDescriptorWithKey:#"creationTime" ascending:NO]];
This would probably be easy to do with a JOIN...
You are right that a fetch request cannot sort the results according to an ordered relationship, so using an "intermediate" entity might be the only solution.
You would then execute a fetch request on the "TagDocumentPair" entity instead of the "Document" entity:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"TagDocumentPair" inManagedObjectContext:managedObjectContext];
request.predicate = [NSPredicate predicateWithFormat:#"tag == %#", selectedTag];
request.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"orderNumber" ascending:NO]];
where "orderNumber" is an attribute of "TagDocumentPair" that describes the ordering
of the documents of a tag.
Since each "TagDocumentPair" points to exactly one "Document", you can display the
document attributes in cellForRowAtIndexPath etc.
A disadvantage of this solution might be that changes to the attributes of a "Document" will not automatically trigger table view updates, because a fetched results controller does
not track changes to related objects.

Core Data fetching many-to-one relationship objects

In my app I have two entities which are Items and Lists. Each item belongs to only one list and each list has many items. Thus in the modal the entities has the following relationships:
For Items: to-one relationship (belongs_to_list) pointing to one list
For Lists: to-many relationship (has_items) pointing to many items
How can I fetch the items using a predicate to check whether the list it's related to is equal to a specific list I provide? I don't want to fetch the items through the list (like fetching objects of has_items). I want to be able to use belongs_to_list in a predicate to compare it to a managed object I have. I tried the following but it's not working. Any help please?
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Items" inManagedObjectContext:_managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"item_detail" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"list.list_name == %#", [self.currentList valueForKey:#"list_name"]];
[fetchRequest setPredicate:predicate];
If I understood well your question, the following predicates would be correct:
[NSPredicate predicateWithFormat:#"belongs_to_list == %#", [self currentList]];
Let me know if this does work for you.

Find Core Data Entities through two 1-to-1 relationships

Boundary <--> Datasets <-->> DataA
I want to find all Entities of DataA that belong to Boundary boundary1;
I tried:
NSPredicate *predication = [NSPredicate predicateWithFormant:#"datasets.boundary.boundaryID == %#", myBoundaryID];
but it has issue when trying to find the Boundary's properties.
My other thought was:
NSArray *savedAnalysis = [NSArray arrayWithArray:[dataset.savedAnalysis allObjects]];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:NAME ascending:TRUE];
NSArray *descriptors = [NSArray arrayWithObject:sortDescriptor];
self.datasourceSavedAnalysis = [NSArray arrayWithArray:[savedAnalysis sortedArrayUsingDescriptors:descriptors]];
But I don't know how to sort the Core Data Entities in the array.
I am not a database guy and I'm having trouble figuring out the logic to this stuff.
Try the following:
NSPredicate *predication = [NSPredicate predicateWithFormant:#"datasets.boundary == %#", myBoundary];
wWhere myBoundary is a Boundary entity.

how to fetch a specific B managed object from a to-many relationship from A to B, based on one of B's attributes?

That is, I have an entity A with a to-many relationship with entity B. B instances have, among other attributes, a creationDate. And I also already have a managed object for A in memory.
So I know I can access all B instances through A's accessor. But I'd like to do something along the lines of:
"for all Bs in A.relationshipName, return the managed object for the B with the most recent B.creationData"
How could I go about it?
How about performing another fetch request:
Assuming the relationship name on the one of the one-to-many side is a
// 1
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"B"
inManagedObjectContext:self.managedObjectContext];
fetchRequest.entity = entity;
// 2
fetchRequest.fetchLimit = 1;
// 3
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"self.a = %#", previouslyFetchedAObject];
// 4
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"creationDate"
ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
fetchRequest.sortDescriptors = sortDescriptors;
In plain English
Make a new fetch request for B
Set the fetch limit so you only return 1 object
Set a predicate that only pulls back objects that have a relationship to the already fetched A object
Set the order descending on date so you get newest dates first
Alternately, since you already have a managed object A in memory, you could do an in-memory filtered sort of the A->>B relationship.
A *inMemoryA = ...
id byDate = [NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:YES];
id sorters = [NSArray arrayWithObjects:byDate, nil];
NSArray *sortedBs = [inMemoryA allBs] sortedArrayUsingDescriptors:sorters];
B *mostRecentB = [sortedBs lastObject];

Resources