HughHughTeotl
HughHughTeotl

Reputation: 5789

NSPredicate on multiple to-many relationships in Core Data

I have an NSPredicate which includes multiple aggregate filters, which is throwing an exception.

I have the following core data model:

Core data model

I want to pick those ApparelItems for which any of the colours has an rgb of 13576743, and for which all of the picks have a pickTime earlier than a given NSDate.

My code to create the predicate is:

let request = NSFetchRequest(entityName: "ApparelItem")
var predicates = [NSPredicate]()

predicates.append(NSPredicate(format: "ANY colours.rgb = 13576743"))

// find the NSDate representing midnight x days ago
let cal = NSCalendar.currentCalendar()
if let xDaysAgo = cal.dateByAddingUnit(.Day, value: -2, toDate: NSDate(), options: [])
{
    let midnightXDaysAgo = cal.startOfDayForDate(xDaysAgo)

    predicates.append(NSPredicate(format: "(ALL picks.pickTime < %@)", midnightXDaysAgo))
}

request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)

let searchData = try? objectContext.executeFetchRequest(request)

I get the following exception:

Exception name=NSInvalidArgumentException, reason=Unsupported predicate (ANY colours.rgb == 13576743) AND ALL picks.pickTime < CAST(479347200.000000, "NSDate")

I have tried:

  1. Each individual predicate works fine. Ie ANY colours.rgb = ... works, also ALL picks.pickTime < ... works. They just don't work when combined into the same query.

  2. Combining the two using into a single query, linked with AND, rather than using NSCompoundPredicate. Result is the same.

Is it possible that core data simply doesn't support filtering on more than one to-many relationship? That would seem odd. In which case how should I do the above?

Upvotes: 6

Views: 1498

Answers (2)

Mundi
Mundi

Reputation: 80265

Colors and picks are two different entities, so you should be able to filter by both without using SUBQUERY. One predicate or a compound predicate should both be fine.

From the error message it seems that perhaps something is wrong with the date. Please check you have the expected data type in your managed object subclasses. If you used "primitive values" when creating the subclasses, you will need NSTimeInterval rather than NSDate.

Upvotes: 0

Allen
Allen

Reputation: 1734

Probably could try SUBQUERY() for NSPredicate.

The code below I came out from some guess and not very sure if it works or not. Usually it takes me trial and error many times for a to-many query clause with NSPredicate.

var predicates = [NSPredicate]()
predicates.append(NSPredicate(format: "SUBQUERY(colours, $colour, ANY $colour.rgb = 13576743).@count > 0"))
let cal = NSCalendar.currentCalendar()
if let xDaysAgo = cal.dateByAddingUnit(.Day, value: -2, toDate: NSDate(), options: []) {
    let midnightXDaysAgo = cal.startOfDayForDate(xDaysAgo)
    predicates.append(NSPredicate(format: "SUBQUERY(picks, $pick, ALL $pick.pickTime < %@).@count > 0", midnightXDaysAgo))
}

Upvotes: 2

Related Questions