问题
I have a many-to-many relationship between two entities; Item and Tag. I'm trying to create a predicate to take the selectedItem and return a ranking of items based on how many similar tags they have. So far I've tried:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SUBQUERY(itemToTag, $item, $item in %@).@count > 0", selectedItem.itemToTag];
Any other iterations that have failed. It currently only returns the selectedItem in the list. I've found little on Subquery. Is there a guru out there that can help me refine this?
Thanks in advance for the help!
Edited 9June
The good news is with Dan's code I'm able to populate the tableview with items! Unfortunately ranking numbers are 0.
Solution I originally tried searching for tags by ID rather than name. Note the two predicate options in 'rankingExpressionDescriptionForTags:' I do not have unique identifier to my tags and use the second of the two options. Thanks Dan!
回答1:
A predicate is only the beginning.
First take a look at THIS VERY similar question.
Assuming your model has an Item
and Tag
entities, related in a many-to-many relationship:Item.tags
<<-->> Tag.items
The answer:
- (NSExpressionDescription*) rankingExpressionDescriptionForTags:(NSSet*)tags
{
NSPredicate* p = [NSPredicate predicateWithFormat:@"SUBQUERY(tags,$t,$t IN %@).@count > 0",tags];
//if your tags are not unique (meaning you only like to match the names of tags)
//change the predicate to:
//p = [NSPredicate predicateWithFormat:@"SUBQUERY(tags,$t,$t.tagName IN %@).@count > 0",[tags valueForKey:@"tagName"]];
NSExpression* rankExpresion = [(NSComparisonPredicate*)p2 leftExpression];
NSExpressionDescription* rankExpDesc = [[NSExpressionDescription alloc] init];
rankExpDesc.name = @"ranking";
rankExpDesc.expression = rankExpresion;
rankExpDesc.expressionResultType = NSInteger64AttributeType;
return rankExpDesc;
}
- (NSExpressionDescription*) objectIDExpressionDescription
{
NSExpressionDescription* expDesc = [[NSExpressionDescription alloc] init];
expDesc.name = @"objectID";
expDesc.expressionResultType = NSObjectIDAttributeType;
expDesc.expression = [NSExpression expressionForEvaluatedObject];
return expDesc;
}
- (NSFetchRequest*) rankingRequestForItem:(NSManagedObject*)item
{
NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:@"Item"];
NSPredicate* p = [NSPredicate predicateWithFormat:@"SELF != %@",item.objectID];
r.resultType = NSDictionaryResultType;
r.propertiesToFetch = @[[self objectIDExpressionDescription],
[self rankingExpressionDescriptionForTags:[item mutableSetValueForKey:@"tags"]]];
r.predicate = p;
return r;
}
Note:
- The resulting array contains dictionaries
- (AFAIK) You will have to sort the resulting array in-memory after the fetch if you like to sort by ranking
- You cannot use a fetched results controller to track changes in these objects
- You can use a FRC to display these items
来源:https://stackoverflow.com/questions/24103508/predicate-subquery-to-return-items-by-matching-tags