For a relationship like this:
TagGroups<---->>Tags<<---->>Object
An Object has tags, tags can be grouped by tagGroups.
I have an object, and I want to know all of the TagGroups its Tags belong to.
To construct he predicate, I first tried the following format string:
(SELF is a TagGroup)
NSPredicate* p = [NSPredicate predicateWithFormat:#"%# IN SELF.tags.objects" , object];
This fails because sets are not traversed ala Key-ValueCoding.
After some research I have found several questions explaining SUBQUERY
Core Data, try to use NSPredicate to filter a toMany relationship set but get the "to-many key not allowed here" error
Core data to-many NSPredicate with AND
These seem to be part of the solution, but unlike these questions I am not testing for a value like "tag.name", but membership within the collection.
So with that in mind I tried this:
NSPredicate* p = [NSPredicate predicateWithFormat:#"%# IN SUBQUERY(SELF.tags, $eachTag,$eachTag.object)" , object];
Which fails to parse (I tried a few other variants unsuccessfully as well)
Any ideas on how to construct this format string properly?
Update:
Also tried it from the other direction:
NSPredicate* p = [NSPredicate predicateWithFormat:#"ALL SUBQUERY(%#.tags,$eachTag,$eachTag.tagGroup)" , anObject];
If you "have an object" i.e. you have a particular managedObject whose entity is Object then you don't need a predicate. You just need to walk the relationship keypath.
Here is an example implemented with dictionaries by it works the same way with a managed object.
NSDictionary *tagGroup1=[NSDictionary dictionaryWithObjectsAndKeys:#"tagGroupOne",#"name",#"tagGroup1",#"theValue",nil];
NSDictionary *tagGroup2=[NSDictionary dictionaryWithObjectsAndKeys:#"tagGroupTwo",#"name",#"tagGroup2",#"theValue",nil];
NSDictionary *tag1=[NSDictionary dictionaryWithObject:tagGroup1 forKey:#"tagGroup"];
NSDictionary *tag2=[NSDictionary dictionaryWithObject:tagGroup2 forKey:#"tagGroup"];
NSSet *tags=[NSSet setWithObjects:tag1,tag2,nil];
NSDictionary *objD=[NSDictionary dictionaryWithObjectsAndKeys:tags,#"tags",nil];
NSLog(#"tagGroup names=%#",[objD valueForKeyPath:#"tags.tagGroup.name"]);
NSLog(#"tagGroup objects=%#",[objD valueForKeyPath:#"tags.tagGroup"]);
... which outputs:
tagGroup names={(
tagGroupTwo,
tagGroupOne
)}
tagGroup objects={(
{
name = tagGroupTwo;
theValue = tagGroup2;
},
{
name = tagGroupOne;
theValue = tagGroup1;
}
)}
So, really all you need is a line like:
NSSet *tagGroups=[anInstanceOfObject valueForKeyPath:#"tags.tagGroup"];
That's the power of key-value coding.
You would only need a subquery if you were trying to fetch Objects that had a relationship to a TagGroup with a particular attribute value.
Related
I have a data model setup with three entities, Course, Student, TestScores.
They are linked in too-many relationships like this:
Course <---->> Student <---->> TestScores
So a Course would have several Students, who in turn could have several TestScores (or no test scores)
The Course entity has a Name attribute. TestScores is a simple entity which just contains a testScore int attribute.
I want to be able to get an array of Students who have at least one textScore of 100, ordered by Course name. Is this possible with NSPredicate?
I think you could have your predicate as
ANY testScores.score == 100
Then put it all together in a fetch request:
NSFetchRequest *req = [NSFetchRequest fetchRequestForEntityNamed:#"Student"];
req.predicate = [NSPredicate predicateWithFormat:#"ANY testScores.score == 100"];
req.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"course.name" ascending:YES]];
I have a mutable array of custom Contact objects who in turn have Address objects.
I want to filter that array by attribute of the object, for example contact.address.pincode using
[myContacts filterUsingPredicate:myPredicate];
So I create a predicate like this :
[NSPredicate predicateWithFormat:#"Address.pincode BEGINSWITH[cd] %# OR Address.pincode CONTAINS[cd] %#",searchText,[NSString stringWithFormat:#" %#",searchText]];
which obviously does not work.
My question is how access Contact.Address.pincode inside the predicate format string?
Thanks
In core data I have an entity called keyword with a property 'text'. I want to find all keyword objects that are contained in a particular sting.
I tried:
[NSPredicate predicateWithFormat:#"%# contains[c] text", myString];
But that crashes. It seems like if it will only work if it's reversed.
The predicate works on the entity, so you have your predicate reversed. Since your entity's text property contains a single word, you'd split the string into multiple words and then test:
// This is very simple and only meant to illustrate the property, you should
// use a proper regex to divide your string and you should probably then fold
// and denormalize the components, etc.
NSSet* wordsInString = [NSSet setWithArray:[myString componentsSeparatedByString:#" "]];
NSPredicate* pred = [NSPredicate predicateWithFormat:#"SELF.text IN %#", wordsInString];
I think you're doing in reverse direction.
Try this.
[NSPredicate predicateWithFormat:#"text contains[cd] %#", myString];
Another way to word this might be...
NSPredicate "state.country == 'United States'"
is like
SQL "Select * from state where state.country = 'United States'
so how do I do this as a predicate?
SQL "Select state.name from state where state.county = 'United States'"
ORIGINAL POST:
I have a dictionary of arrays of dictionaries that looks like this:
lists
states
state
country
country
country
I have code to filter states by country. However, I'm betting there is a cleaner way.
NSArray *states = [lists valueForKey:#"states"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"countryname == %#", selectedCountry];
states = [states filteredArrayUsingPredicate:predicate];
states = [states valueForKeyPath:#"state"];
Ideas?
You've almost got it:
NSDictionary * lists = ...;
This is your original dictionaryl
NSArray *states = [lists objectForKey:#"states"];
This is to retrieve the array of states from your dictionary. Presumably these are actual "State" objects (ie, you made a class called State)
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"countryname == %#", selectedCountry];
This creates a predicate that will compare the results of -[State countryname] to the value referenced by the selectedCountry variable. Alternatively, if the states array contains dictionaries, this will compare the results of -[NSDictionary objectForKey:#"countryname"] to the value referenced by selectedCountry.
states = [states filteredArrayUsingPredicate:predicate];
This will retrieve all the states from the array where [[aState countryname] isEqual:selectedCountry]
states = [states valueForKeyPath:#"name"];
This will create a new array that contains the name of each state. This new array will be in the same order as your filtered states array.
I'm only using NSArray and not NSDictionary so I don't know how useful this is but I'm using this:
matchingTour = [self.tours filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"tourCode == %#", tourCode]];
where self.tours is an NSArray of Tour objects. A Tour object has a property of NSString *tourCode. matchingTour is of type NSArray.
I was amazed when I read about this, tried it and it worked first time and I got back an array containing just the one tour!
In your 'tree' you don't show any property name 'countryname' - just wondering.
i struggling around NSFetchRequest these days.
My data model look like this:
Post <->> Category
Now i need a fetch request to get all posts where the category.name attribute is not "xxx".
Looking at the documentation for NSFetchRequest is should be:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"NONE category.name == %#", categoryName]
But this results in an empty list (the request is used by NSFetchedResultsController in an UITableView.
The docs say:
NONE
Specifies none of the elements in the following expression. For example, NONE children.age < 18. This is logically equivalent to NOT (ANY ...).
If i invert my predicate to
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY category.name == %#", categoryName]
the list contains exactly the objects i want to be excluded from that list.
What am i missing here?
thanks in advance
The predicate form you have is correct.
The simplest explanation is that you have no objects that match the "#"NONE category.name == %#" predicate. That would explain why the inverse works.
I suggest that you:
Log the predicate with NSLog and see what the predicate actually is each time
Fetch all Post objects compare the count of objects returned with the count of objects returned by the "ANY" predicate. If they are the same then...
...log the category.name values to see if any of them do match the "NONE" predicate.
I think that should allow you to find the problem.