predicate subquery to return items by matching tags

此生再无相见时 提交于 2019-12-11 21:02:08

问题


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:

  1. The resulting array contains dictionaries
  2. (AFAIK) You will have to sort the resulting array in-memory after the fetch if you like to sort by ranking
  3. You cannot use a fetched results controller to track changes in these objects
  4. You can use a FRC to display these items


来源:https://stackoverflow.com/questions/24103508/predicate-subquery-to-return-items-by-matching-tags

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!