I'm not certain how one would go about "cascading" several conditions into an NSPredicate.
I'm fairly new to Core Data and not sure if that's the right way to achieve what I am looking to do.
Here is what I am trying to do:
There is a Photo object that has a whereTook relationship to a Location object, which has an inverse of photosTookThere.
The Photo in turn has an NSNumber attribute called isFavourite.
I'd like to configure an NSFetchRequest that will first check that photosTookThere exists and if so, check each resulting Photo object and return only the ones that are set as favourites.
Here is the code so far:
request.entity = [NSEntityDescription entityForName:#"Location" inManagedObjectContext:context];
request.sortDescriptors = [NSArray arrayWithObject[NSSortDescriptorsortDescriptorWithKey:#"locationId" ascending:YES]];
request.predicate = [NSPredicate predicateWithFormat:#"photosTookThere.#count != 0"];
How would I cascade the second condition into the predicate and return the correct results?
Just put each condition inside of parentheses and connect them with AND.
[NSPredicate predicateWithFormat:#"(photosTookThere.#count != 0) AND (isFavourite == %#)", [NSNumber numberWithBool:YES]];
I'd also recommend changing the name of your "whereTook" relationship to "location", and your "photosTookThere" to simply "photos", that's more in line with convention.
I eventually was able to solve this using a subquery:
request.predicate = [NSPredicate predicateWithFormat:
#"(photosTookThere.#count !=0) AND SUBQUERY(photosTookThere, $Photo, $Photo.isFavourite==1).#count >0"
];
You can very simply use AND and OR in your predicate much like you would if you were specifying a "where" condition in an SQL statement. To check for a NULL, which it looks like you want when comparing against "whereTook", you can compare to nil (whereTook = nil).
Related
NSMutableArray *arrayOfPredicates=[[NSMutableArray alloc]init];
[self.attendeeListSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop){
NSString *userId=[obj userId];
[arrayOfPredicates addObject:[NSPredicate predicateWithFormat:#"userID == %#",userId]];
}];
NSPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:arrayOfPredicates];
[request setPredicate:compoundPredicate];
I am setting this compound predicate for multiple userIds in an array and i need to get the Users from those User ids using OR.
The above is not working but when I'm hardcoding using
NSPredicate *predicate1=[NSPredicate predicateWithFormat:#"(userID like[cd] %#)
OR (userID like[cd] %#)",#"sheetal2", #"sheetal3"];
[arrayOfPredicates addObject:predicate1];
Now this is working..Can anyboady tell whats the problem with my code..
Thanks
In your first code the predicate uses ==. In the second code the predicate uses LIKE[cd]. Because the userID is an NSString, using LIKE is generally a better way to tell the predicate to compare the values, but the real difference is that the second approach is case and diacritic insensitive and the first approach requires an exact match.
i need to imlement search with to different class ons is Song and the other one is Album. etch one of them is represent song/album with his property (name,url,etc..).
now i am using this code to search song from my songArray by searching the name property, i need to also be able to search in the albumArray, also in the name property.
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
// Update the filtered array based on the search text and scope.
// Remove all objects from the filtered search array
[self.filteredSongArray removeAllObjects];
// Filter the array using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF._songName contains[cd] %#",searchText];
filteredSongArray = [NSMutableArray arrayWithArray:[_myDataMgr.songArray filteredArrayUsingPredicate:predicate]];
}
so my qustion is how can i tell the the predicate to look also in the AlbumArray
thank you all.
UPDATE:
i ran another predicate on the AlbumArray and after i got the results i added the two arrays. thank your replay was very helpful!
You can filter the array contents like this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(songName CONTAINS[cd] %#)", searchText];
[self.filteredSongArray addObjectsFromArray [_myDataMgr.songArray filteredArrayUsingPredicate:predicate]];
No need to add SELF in predicate....
Hope this helps...!!!
Hey,
I have an Array of NSDictionaries (e.g. [tempArray addObject:[[[NSMutableDictionary alloc] initWithObjects:someArray forKeys:keys] autorelease]]; ) and when I try to search through it with NSPredicate it keeps giving me 'No Results'. (TempArray becomes self.patientList)
I have no compile-time warnings or errors, and if I NSLog([self.filteredArray count]); then it returns 0 as well.
Here is my relevant code:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(first contains[cd] %#)", self.searchBar.text];
self.filteredArray = [self.patientList filteredArrayUsingPredicate:predicate];
return [self.filteredArray count];
self.patientList and self.filteredArray are types NSMutableArray and NSArray respectively (changing self.filteredArray to NSMutableArray doesn't help).
I have tried using == instead of contains as well. Using #"SELF contains[cd] %#" only returns an item when the full item is typed (i.e. if the key 'name' is #"Bob" then if I type in Bob it will display it, but not when I type Bo or ob).
I'm really stumped on this one.
Thanks in advance!
Apparently first is a reserved word when using predicates. From Apple's documentation:
The following words are reserved:
AND, OR, IN, NOT, ALL, ANY, SOME,
NONE, LIKE, CASEINSENSITIVE, CI,
MATCHES, CONTAINS, BEGINSWITH,
ENDSWITH, BETWEEN, NULL, NIL, SELF,
TRUE, YES, FALSE, NO, FIRST, LAST,
SIZE, ANYKEY, SUBQUERY, CAST,
TRUEPREDICATE, FALSEPREDICATE
Just change your key to something else, firstName perhaps, and it will work.
You can use "like" instead:
first like[c] *%#*
At first glance, it seems correct. So then: do your dictionaries actually have a key called first? And if they do, does it match the case exactly?
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.
I have a NSFetchedResultsController which is fetching objects from a NSManagedObjectContext.
These objects have a lastOpened property, which is initially nil and is only set when they are viewed.
I want my UITableView to display a list of the most recently opened objects, which I can do by adding a NSSortDescriptor to the NSFetchRequest.
Question:
I don't want to display the objects which have never been studied. (lastOpened == nil) Can I sort this via the same NSFetchRequest? Is there a better way to filter the data?
Thanks.
Absolutely. What you're looking for is an NSPredicate. Basically, it allows you to specify one or more conditions that you want your fetched objects to meet, then only fetches objects that match those conditions.
Building predicates is a slightly tricky proposition, however - you might want to take a look at the Predicate Format String Syntax guide to get started. For your particular case, it's even trickier since I'm not sure there's a representation for the nil value in predicate terms. You can get around this, however, by using some date in the distant past:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"lastOpened > %#",
[NSDate dateWithTimeIntervalSince1970:0]];
You can just check against nil directly in a predicate:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"lastOpened != nil"];
This creates a predicate that only allows objects with a set date (anything after January 1, 1970) to be returned. You'd then add the predicate to the fetch request before you execute it:
// Assuming you have some almost-ready NSFetchRequest *request:
[request setPredicate:predicate];
Try this:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"lastOpened != nil"];
... // add sort descriptors etc.
Then add the fetch request to the NSFetchResultsController.
For Swift, you can initialize NSPredicate with a boolean to always return true, effectively a filter that doesn't filter anything
return fetchedResultsController("Terminal", withFilter: NSPredicate(value: true), sortColumns: sortColumns, sortDirections: sortDirections)