NSPredicate nested dictionary dynamic key - ios

I am using core data to fetch a list of objects. These objects have a property named 'categories'. This categories property is a NSDictionary constructed from json like :
#{#"A":#YES, #"B":#NO, #"C":#YES}
I want to get all core data objects which category is true for a given category key.
I tried :
NSString *categoryKey = #"A";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"categories.%K == YES", categoryKey]];
// or
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.categories.%# == YES", categoryKey]];
// or
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"categories[%#] == YES", categoryKey];
// Throws exception : Unsupported function expression categories["A"]
// or
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"categories[%K] == YES", categoryKey];
// Throws exception : Unsupported function expression categories[A]
// or
NSString *categoryKeyPath = [NSString stringWithFormat:#"categories.%#", categoryKey];
NSPredicate *p = [NSPredicate predicateWithFormat:#"%K == YES", categoryKeyPath]];
But it always returns empty array when performing my fetch (of course I have some objects with categories[#"A"] = YES).
I think the problem comes from nested dictionary key path but I can't find a way to achieve this with one predicate.
Edit:
To clarify I would use
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [[evaluatedObject.categories objectForKey:categoryKey] boolValue];
}];
But predicateWithBlock: is not supported when fetching in core data.

If I understand correctly categories is a string attribute on your entity, which contains JSON data, and your managed objects parse this JSON so it can be read as a dictionary.
The problem is that the managed objects are not created before the fetch is performed. At that point, categories is just a string, and no key path will be able to extract the info you want from it. You will need to fetch all the objects so they can construct their dictionaries, then filter that collection. For large data sets, this may be slow.
Core Data is designed to be used by explicitly modelling the data; if you jam your own data structure inside a string, Core Data can’t help you. The more idiomatic design would be to have a Categories entity with a to-many/to-many relationship with the entity of your object. This makes it trivial to find all the objects in category A by fetching category A then following the relationship.

Try this
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.categories LIKE \"%#\":true", categoryKey]];

Related

NSNumber property of NSManagedObject with NSPredicate

Here I have attribute (name :- universal_Id) in core data as NSNumber in modal class
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"universal_Id == %d",0];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"universal_Id == %d",[NSNumber numberWithInt:0]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"universal_Id == %#",[NSNumber numberWithInt:0]];
Please provide me some correct solution for above predicates. Which one is the correct way to fetch data on the bases of universal_Id?
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"universal_Id == %d",0];
is correct because Core Data is ORM and uses objects to represent scalar values. So when you need to store data in core data , you need to use objects. In predicate building, here you need not to use objects, scalar value is enough to build a predicate, because at the end, core data query matches the universal_Id value, not the object.
Update
you can also use
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.universal_Id == %d",0];

Core Data Predicate - Check if any element in array matches any element in another array

I'm trying to use a predicate to filter objects where an intersection exists between two arrays.
The NSManagedObject has an array(Of Strings) attribute named "transmissions". And there is another array(Of Strings) that will contain words to filter by, named "filters".
I'm not sure how to find if any elements in "transmissions" match any element in "filters".
I've tried
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY SELF.transmission in[c] %#",transmissions];
or
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY transmission in[c] %#",transmissions];
However, core data fetches no results where there should be some.
Try this.
NSPredicate *predicate = nil;
NSMutableArray *predicates = [NSMutableArray new];
for (NSString *transmission in transmissions) {
[predicates addObject:[NSPredicate predicateWithFormat:#"transmission == %#", transmission]];
}
if (predicates.count > 0)
predicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicates];
// make fetch request using 'predicate'
You can use the keyword CONTAINS to check an object exists in a collection.
[NSPredicate predicateWithFormat:#"favouriteFilms CONTAINS %#", film]
I believe the same thing can be achieved with IN by switching the LHS and RHS of the predicate. I have only successfully implemented this functionality using CONTAINS however.

NSPredicate format evaluateWithObject with nsarray containing nsdictionaries

Is there any cookbook for NSPredicate format? I'm wonder how to test NSArray with dictionaries, if one of them contains a value "adult" for key "type" as shown in an example below:
NSDictionary* passengers = #[#{#"type":#"child"},#{#"type":#"adult"}];
NSPredicate* testPredicate = [NSPredicate predicateWithFormat:#"ANY SELF.type LIKE[c] adult"];
BOOL adultOnBoard = [testPredicate evaluateWithObject: passengers];
DO NOT MIX WITH filtering array - I expect testing as a "cheap" operation comparing to filtering.

How to find an object with a specific property which is in the array of an array, by using NSPredicate?

Suppose I have the following objects
class A {
NSArray *arrayOfB;
}
class B {
NSString *name;
}
Now, I have an array of As like below and each A contains 10 objects of B within its property arrayOfB.
NSArray *arrayOfAs; //contains objects of A
How can I get the objects of A depending upon specific match of name property of Bs inside of A, by using NSPredicate ?
I've tried googling, etc. and even writing various style of NSPredicate but did not succeed. Can anyone enlighten me how to do it?
This is what I tried so far:
NSPredicate *p = [NSPredicate predicateWithFormat:#"(SELF.name BEGINSWITH[c] %# IN SELF.arrayOfB)",myText];
NSArray *mySearchedArrayOfAs = [arrayOfAs filteredArrayUsingPredicate:p];
But I run into error which says "Unable to parse the predicate".
I think you need to use ANY operator, like this:
NSPredicate *p = [NSPredicate predicateWithFormat:#"ANY arrayOfB.name BEGINSWITH[c] %#", myText];

NSPredicate find object with attribute in NSSet

I have an NSMangedObject that contains NSSet of other NSManagedObjects.
I need to check if these objects has an value in NSSet and then return them.
I use MagicalRecord for fetching data.
So I need something like this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"stringObjects contains %#", string];
So if NSSet stringObjects contains some string that I am looking for so then return object I have requested.
One note here: stringObjects (name just for example it represent my NSSet) it is NSSet that contains NSManagedObjects, so I need to search them by some id (for example string_id attribute).
So then model looks like this
NSSet *set = MainObject.stringObjects;
NSString *string_id_for_first_object = [[[set allObjects] objectAtIndex:0] string_id];
Just for better understanding relationship.
But the question is about how can I create predicate to check if NSSet contains needed id.
If I understand your question correctly, stringObjects is a to-many relationship
from one entity A to another entity B, and B has an attribute string_id.
To find all A objects that are related to any B object with the given string id, use:
NSString *stringId = …; // The string that you are looking for
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY stringObjects.string_id == %#", stringId];

Resources