NSPredicate count on a relationship attribute - ios

I have actually a core data entity called Show and for every show I have a relation ship called Schedule that contains an attribute called schedules which is an array.
What I want to do is to create a Predicate that checks for a given show's schedule if it has more than 1 item.
To do That I tried Two solutions :
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"schedule.schedules > 1];
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"schedule.schedules.#count > 1];
But None of them would work.
NB : schedules attribute is an stored in my Core Data as Transformable and declared as an id variable.

A transformable attribute is stored as binary data, and it isn't unpacked until the container entity is loaded into memory. So, you can't use any kind of predicate based on a transformable attribute in a fetch. It will only work to filter the results of the fetch.
Cheap solution is to store a simple integer attribute with the count and use that.
Better solution is likely to add / change your entities so you use a relationship instead of a transformable.

Did you try this?
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"#count.schedule.schedules > 1];

Related

How to use NSPredicate to filter objects by the element of their NSSet property in CoreData?

I have two class, one is named Folder, the other is named Entry.
In my data model, a folder would contain multiple entry, and an entry can be contained by different folders.
So each folder has a folderID to identify itself, and a relationship named entries which is used to contains Entry instances. And each entry has an inverse relationship named superFolders which points back to the folder contains it.
Now is my question. Here I get a folderID. I want to use this and NSFetchRequest to fetch all the entries contained by this special folder in Core Data. The following is the main code:
let fetchRequest = NSFetchRequest<Entry>(entityName: "Entry")
fetchRequest.predicate = NSPredicate(format: "(ANY folder in %K).folderID = %i", #keyPath(Entry.superFolders), folerID)
The format string in above code is incorrect, but it mostly explain what I mean. Since superFolders property is actually a NSSet in Core Data, I can't use superFolders.folderID == %i as the judge condition. What exactly I want is to find all the entry whose superFolder property contains any of element which its folderID property match the given folderID.
So is that possible to use NSPredicate to express what I mean to Core Data ?
You want:
let fetchRequest = NSFetchRequest<Entry>(entityName: "Entry")
fetchRequest.predicate = NSPredicate(format: "ANY superFolders.folderID = %#", folderID)
See the NSPredicate reference
If you had a more complicated match on the superFolders relationship, you would need to use SUBQUERY, but in this case a simple ANY predicate works fine.

NSPredicate a relationship objects

i'm working with core data and i've two tables
List
ListItems
ListItems has a relationship named "parentlist" with destination set to "List"
I'm trying to query the ListItems for all the listItems whoes parent is X (List object)
i've tried this approach but it's not working
List* myList; // Initialized form other views
NSPredicate *pred = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"List == %#",myList]];
If you have an inverse relationship listItems (as Apple recommends) you can use just:
myList.listItems
There are two problems in your code: In the predicate you have to use the relationship ("parentList"),
not the target entity ("List"). And you should not mix string formatting with
predicate formatting.
To get all ListItems related to the given list, the predicate would be
List* myList = ...;
NSPredicate *pred = [NSPredicate predicateWithFormat:#"parentList == %#", myList];
I'm assuming you're looking for something other than simply accessing the listItems through the list? If so :
comparing objects in core data doesn't really work that way.
You could do this in one of two ways,
Easy : Assign the lists a GUID on creation using :
[[NSProcessInfo processInfo] globallyUniqueString]
and use this for comparing two lists.
Harder : implement a comparison function on the objects by overriding compare and compare the objects in a way that makes sense to you.
- (NSComparisonResult) compare : (List *) other;
Then create a NSPredicate using blocks.
You could also use a GUID and use it in the compare function, thus allowing you to expand on this later.

Using NSFetchRequest with complex NSPredicate in a NSFetchRequestController

Im trying to implement something that I'm sure have been implemented a million times before, a search in the core data database, displayed in a table using a fetchRequestController and the searchController.
My problem is writing the NSPredicate for the NSFetchRequest. According to the NSPredicate guide by Apple, not everything you can do in Sqlite is possible with core data.
I have been trying to find a solution for some time, but maybe one of you can use his experience to help me.
CoreData DB description:
Shops has a MANY TO MANY relationship with DiscountProgam.
My use case is as follows: I need to filter out Shops who's name/address/zip/city contains the search string. that's the easy part.
The hard part is creating the section of the database I want to filter from, because I have an array of "active" discountPrograms UID's, and I only want shops that have one of the active discount programs in their "discountPrograms" set. So in pseudo code that would be:
FROM Shops who have at least one discountProgram who's uid IN activeDiscountProgramsArray WHERE name/address/zip/city CONTAINS searchString
Is this possible? am I over reaching the limits of predicates?
If so, how could I do it differently?
Yes, NSPredicate can analyse both the direct attributes of the target entity of a fetch and the attributes of its relationships. Try:
NSArray *validUIDs = ...;
NSString *searchTerm = ...;
[NSPredicate predicateWithFormat:#"(name CONTAINS[cd] %# OR zip CONTAINS[cd] %#) AND (SUBQUERY(discountProgram, $d, $d.UID IN %#).#count > 0)", searchTerm, searchTerm, validUIDs];

"IN" NSPredicate where the search is made within an array of objects

I have an array called deletedDepartments which contains NSObjects called DeletedObject. A DeletedObject only has a field called deletedID. This array is generated from a mapping with RestKit.
Now, I want to search within CoreDate for Department objects where their id is within the deletedDepartments array.
If I do
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"id IN %#", deletedDepartments ]];
This won't work because deletedDepartments is not a NSArray made of NSNumber, but of NSObject which contains the NSNumber I want to compare. How can I achieve such thing without creating another array made from iterating over the deletedDepartments and selecting only the deletedID?
Change your predicate to the following :
[NSPredicate predicateWithFormat:#"deletedID IN %#", [deletedDepartments valueForKey:#"deletedID"]]
This will create an array of your deletedId's, and evaluate each object using the deletedId property. While, yes, this does internally iterate over the array to create a new one, that's the best you can do unless the NSObjects in deletedDepartments are of the same class as the model objects that your are fetching.

Core Data with to Many relationship - Creating a NSPredicate with ALL in SUBQUERY

My object graph looks like this
SnapShot -->> Pane --> ManagedImage
I'm trying to find a SnapShot that has the exact ManagedImages contained with in a set.
The code I've got now returns an Array of SnapShots that have one or more of the ManagedImages that are in the set. I then search through the Array to find the correct SnapShot but I'm guessing it would be much faster to filter in the Subquery
With an NSPredicate how can I get the unique SnapShot that has ALL of the ManagedImages that are in the set?
Here's my code
mySet = ... // A unique set of (usually 3) managedImages that I'm trying to find a snapShot for
NSFetchRequest *request = ...
request.entity = [NSEntityDescription entityForName:#"SnapShot" inManagedObjectContext:[self managedObjectContext]];
// Want this to work but sends an exception
//request.predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(self.panes, $pane, ALL $pane.managedImage IN %#).#count != 0", mySet];
// Using this
request.predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(self.panes, $pane, $pane.managedImage IN %#).#count != 0", mySet];
A good rule of thumb is that if you already have managed objects in hand, you don't fetch but instead walk the relationships from the managed objects you have to the managed objects you want.
So, your relationship graph probably actually looks like this:
SnapShot <-->> Pane <--> ManagedImage
or maybe:
SnapShot <<-->> Pane <<--> ManagedImage
Since you have a set of ManagedImage objects all you have to do is walk the keypath of pane.snapShot or panes.snapShots to find the SnapShot objects associated with each ManagedImage object. Then you just extract the unique SnapShot objects.
In the first case, the matter is trivial because of the one-to-one relationship path of
ManagedImage-->Pane-->SnapShot
In the second case, you will need to first get all the unique SnapShot objects:
NSSet *shots=[aMangedImageObj valueForKeyPath:#"distinctUnionOfSets.panes.snapShots"];
... for each ManagedImage instances and then merge all the sets with setByAddingObjectsFromSet: or a similar method to produce a single set of unique objects.
Fetches should be used to find the first objects in graph that you need but once you have the objects, you don't fetch but walk the relationships. Otherwise, there is not much point to having relationships in the first place.

Resources