accessing values using multiple relationships with NSPredicate - iphone

here is my core data model:
Locations < --- >> ThemesList << --- > Themes
The entites have the following attributes:
Locations
- Property: Name
- Relationship: ThemesList
ThemesList
- Relationship: Locations
- Relationship: Themes
Themes
- Property: Name
- Relationship: Locations
I am running a fetch on entity Locations and I want to only pull values where the name property in Themes is equal to a particular value. Based on what I've read, I need to do a subquery. I've tried something along the lines of the code below, but I always receive the error of Unable to parse the format string
[NSString stringWithFormat:#"SUBQUERY(ThemesList, $theThemes, $theThemes.Themes.Name LIKE %#)", #"a theme name"];
Any ideas on how I can accomplish this - what am I doing wrong?
Thanks

As a rule of thumb, you should fetch the objects of the entity you are testing with the predicate instead of starting with another entity altogether and walking a relationship inside the predicate. Walking relationships, especially to-many relationships inside of predicates is computationally intensive and slow.
Instead, I would recommend running the fetch against the Theme entity and then just ask the returned Theme objects for their associated Locations objects.
Your predicate would simplify to just:
NSPredicate *p = [NSPredicate predicateWithFormat:#"Themes.Name LIKE %#", #"a theme name"];
Then use a collection operator to find the location objects:
NSSet *locations=[fetchedThemes valueForKeyPath:#"#distinctUnionOfSets.locations"];

Your problem is this: $theThemes.Themes.Name. The parser will want to parse it as a variable expression (since it starts with a $), but when it comes across the ., it's going to produce an error.
As it turns out, the SUBQUERY is unnecessary. That same query can be effectively done as:
NSPredicate *p = [NSPredicate predicateWithFormat:#"ANY ThemesList.Themes.Name LIKE %#", #"a theme name"];
Hopefully Core Data will have an easier time handling that than the SUBQUERY.

Related

NSPredicate with to-many to-many relationships

I am having some trouble writing a predicate for my NSFetchedResultsController to get all Modifier from a table where where Exercise and Modifier contain the same Exercise_Modifier
The model look like this: Exercise <->>>Exercise_Modifier<<<->Modifier
I've tried using ANY and ALL keywords but cannot seem to get to the answer. I've tried this along the line of this:
fetchRequest.predicate = NSPredicate(format: "ALL exercise_modifiers == %#", exercise!.modifiers!)
where exercise_modifiers is the relationship from Modifier <->>>Exercise_Modifier and exercise!.modifiers! are the Exercise_Modifier for the current exercise I have. Does anyone know where I might be missing something?

How to use Dynamic Multiple NSPredicate from NSArray in Core data

I am fairly new to core data. I have database which contains articles with different categories. I want to fetch data from multiple categories, which can be selected by user on the fly. Now I have NSArray which contains selected multiple categories (count from 1 to n) I want to add predicate for selected categories but I'm not able to do so. as per my knowledge i have added for loop for adding categories in predicate but it is not working.
for i in 0...(catArray?.count)!-1 {
let str = String(format:"catId = %#",(catArray?.object(at: i) as? NSNumber)!)
predicateString = predicateString+str
}
let dP = NSPredicate(format:"%#",predicateString)
fetchedRequest.predicate=dP;
but app is crashing while fetching request.
Is there any other way to do it?
Please help me with this.
Any help is much appreciated.
To select objects which have any category from the given array
a simple predicate is sufficient:
NSPredicate(format: "catId IN %#", catArray)
Remark: Never use String(format:) to build predicates dynamically,
because almost surely the quoting and escaping will be wrong.
Use only NSPredicate(format:) and, if necessary, NSCompoundPredicate.

How to verify that NSMutableArray of entity contains object with certain attribute

Based on the data model here: Photographer<------->>Photo
When the user goes to add a Photo, the user also specifies what Photographer took said picture. When the user decides to save the Photo, there is the possibility that the Photographer doesn't exist yet. After executing a NSFetchRequest to get a list of all instances of Photographer, how do I check if the NSMutableArray(photographerArray) contains an object that has the same fullName attribute as what the user is currently adding?
The naive way would be to simply get all the fullName of the array and check if it's in it.
BOOL photographerExist = [[listOfPhotographer valueForKey:#"fullName"] containsObject:enteredFullName];
However, it would be way more easier to put that directly in your fetch request. Just add a predicate to it.
NSPredicate *fullNamePredicate = [NSPredicate predicateWithFormat:#"fullName = %#", enteredFullName];
fetchRequest.predicate = fullNamePredicate;
If the result of the fetch is empty, then the photographer doesn't exist yet.

Core Data: Subquery Performance Problem

I've been trying to see if there is any way I can improve on the performance of the following Predicate:
[NSPredicate predicateWithFormat:#"A=%# and SUBQUERY($self.words,$k,$k.keyword IN %#).#count==%d",
<value for A>,
keywordList,
[keywordList count]];
What I'm trying to do is return all the records of A that have keywords that are ALL contained in the supplied array (keywordList). I have a small database of about 2000 records. However, the keywords for each Entity ranges from 40-300 keywords. The keywords are represented as a to-Many relationship from A to an entity called Keywords. The above query works but takes about 7 seconds to run on my iPhone4. I want to see what I can do to shrink that down to a sub-second response.
Thanks,
Michael
This doesn't quite solve the problem as the results that come back from intersection of the fetchedObjs is not correct. It doesn't guarantee that all the 'A' objects contain all the supplied keywords. In fact, what comes back is an empty list and the entire process actually takes longer.
Something must be wrong with my model or the previous answer. I'm not getting the results I'm expecting. One alternative to returning a list of 'A' would be to return a list of ManagedObjectIDs of 'A'. [mo valueForKey: (NSString *)] returns the object of the relationship.
Note: I originally posted this question anonymously thinking I was logged in, so i can't seem to comment on anybody's answer.
I think you are approaching the problem backwards. If you have the keywords, you should search for the Keyword objects and then walk their A relationships to find the related A objects. Then check for overlap in the relationship sets.
So something like:
NSFetchRequest *fetch=//...set up fetch
[fetch setEntity:Keyword_entity];
NSPredicate *p=[NSPredicate predicateWithFormat:#"keyword IN %#",keywords];
[fetch setPredicate:p];
NSArray *fetchedObj=//... execute fetch
NSMutableSet *inCommon=[NSMutableSet setWithCapacity:[fetchedObjs count]];
for (NSManagedObject *mo in fetchedObjs){
if ([inCommon count]==0){
[inCommon addObjects:[mo valueForKey:#"aRelationshipName"]];
}else{
[inCommon intersectSet:[mo valueForKey:#"aRelationshipName"]];
}
}
... inCommon would then contain a set of all unique A objects that shared all the keywords.
Update:
From OP author:
This doesn't quite solve the problem
as the results that come back from
intersection of the fetchedObjs is not
correct. It doesn't guarantee that all
the 'A' objects contain all the
supplied keywords.
Okay, lets take another tack. Assuming you have a data model that looks something like this:
A {
keywords<<-->>Keyword.as
}
Keyword{
keyword:string
as<<-->>A.keywords
}
Then something like this should work:
NSFetchRequest *keyWordFetch=//...set up fetch
[keyWordFetch setEntity:Keyword_entity];
NSPredicate *p=[NSPredicate predicateWithFormat:#"keyword IN %#",keywords];
[keyWordFetch setPredicate:p];
NSArray *fetchedKeywords=//... execute keyWordFetch
NSFetchRequest *entityAFetch=//...set up fetch
[entityAFetch setEntity:A_entity];
NSPredicate *pred=[NSPredicate predicateWithFormat:#"ALL keywords IN %#", fetchedKeywords);
[entityAFetch setPredicate:pred];
NSArray *fetchedAs=//... execute fetch

sorting people by their role on a company

Im trying to find a good way to sort people by their Role within a specific company. What makes it tricky, is that a person can have one or more roles in different companies.
At the moment I have an array of 'Person' objects, and each of these objects has a NSSet of 'Roles' objects associated to it.
Similar to this:
Person
-personId
-personName (NSString)
-personRoles (NSSet)
Role
-roleId (NSNumber)
-roleWeight (NSNumber)
-roleName (NSString)
-companyId (NSNumber)
I need some code that is able to solve something similar to this:
Sort Array of Person by Role.roleWeight Where Role.companyId = X
I have been looking at the Sort Descriptors, but they dont seem to be enough to solve the challenge. Any suggestions are welcome.
You'll want to look at this
How to sort an NSMutableArray with custom objects in it?
The basic idea is that given any two Person objects, you have to say how they compare. Is one less, greater, or are they the same.
- (NSComparisonResult)compare:(id)otherObject {
// get the role for self
// get the role for other object
// compare their weights
// return the right result
}
To pass in the company id, I think you'll need sortUsingFunction:context:, with a function like this
static int comparePersonsUsingCompanyID(id p1, id p2, void *context)
{
// cast context to a company id
// get the role for p1
// get the role for p2
// compare their weights
// return the right result
}
Assuming that you use NSArray to store data (on maybe CoreData store) you can use NSArrayController. Controller supports sort descriptors and NSPredicate as well. In your case you need a predicate to filter people (where role.companyId = x) and sort descriptors to sort by roleWeight.