ryancrunchi
ryancrunchi

Reputation: 475

NSPredicate nested dictionary dynamic key

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.

Upvotes: 0

Views: 905

Answers (2)

Saif
Saif

Reputation: 2968

Try this

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

Upvotes: 0

Douglas Hill
Douglas Hill

Reputation: 1547

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.

Upvotes: 1

Related Questions