objective c - Filtering many-to-many count expression using existing subquery -
in app, have many-to-many relationship between tags , links follows :
tags <<-->> links
i trying return list of tags relate links have active tags, not included in active tags.
i want obtain count of number of links have 'other' tags, needs limited active tags.
using below, have been able return 'other' tags , count of links, count returned of links each tag.
i able count links using similar approach 1 i'm using build subquery, struggling work. have tried using subquery generated in count nsexpression, errors when subquery evaluated.
// test array of tag names self.activetagarray = [@[@"tag1", @"tag2"] mutablecopy]; nsfetchrequest *fetchrequest = [nsfetchrequest fetchrequestwithentityname:[tag entityname]]; // want exclude tags active nspredicate *activetagspredicate = [nspredicate predicatewithformat:@"not name in %@", self.activetagarray]; // build subquery string identify links have of active tags in tag set nsstring __block *subquery = @"subquery(links, $link, "; [self.activetagarray enumerateobjectsusingblock:^(id tagname, nsuinteger index, bool *stop) { if (index == self.activetagarray.count - 1) { subquery = [subquery stringbyappendingstring:[nsstring stringwithformat:@"subquery($link.tags, $tag, $tag.name = '%@') != null", tagname]]; } else { subquery = [subquery stringbyappendingstring:[nsstring stringwithformat:@"subquery($link.tags, $tag, $tag.name = '%@') != null , ", tagname]]; } }]; subquery = [subquery stringbyappendingstring:@") != null"]; nslog(@"subquery : %@", subquery); nspredicate *notagspredicate = [nspredicate predicatewithformat:subquery]; // create predicate array nsarray *predicatearray = @[notagspredicate, activetagspredicate, userpredicate]; nspredicate *compoundpredicate = [nscompoundpredicate andpredicatewithsubpredicates:predicatearray]; fetchrequest.predicate = compoundpredicate; fetchrequest.relationshipkeypathsforprefetching = @[@"links"]; // set count expression nsexpression *countexpression = [nsexpression expressionforfunction: @"count:" arguments:@[[nsexpression expressionforkeypath: @"links.href"]]]; nsexpressiondescription *expressiondescription = [[nsexpressiondescription alloc] init]; expressiondescription.name = @"counter"; expressiondescription.expression = countexpression; expressiondescription.expressionresulttype = nsinteger32attributetype; fetchrequest.propertiestofetch = @[@"name", expressiondescription]; // sort tag name nssortdescriptor *sortdescriptor = [nssortdescriptor sortdescriptorwithkey:@"name" ascending:yes]; fetchrequest.sortdescriptors = @[sortdescriptor]; fetchrequest.resulttype = nsdictionaryresulttype; nserror *error = nil; nsarray *resultsarray = [self.managedobjectcontext executefetchrequest:fetchrequest error:&error]; if (error) { nslog(@"error : %@", [error localizeddescription]); } nsmutablearray *alltags = [[nsmutablearray alloc] init]; (nsdictionary *tagdict in resultsarray) { nslog(@"tag name : %@, link count : %@", tagdict[@"name"], tagdict[@"counter"]); [alltags addobject:tagdict[@"name"]]; } [alltags addobjectsfromarray:self.activetagarray];
any appreciated!
if understand question correctly, following predicate fetches "other tags", i.e. tags related link related of given "active tags":
nsarray *activetags = @[@"tag1", @"tag2"]; nsfetchrequest *request = [nsfetchrequest fetchrequestwithentityname:@"tag"]; nspredicate *p1 = [nspredicate predicatewithformat:@"not name in %@", activetags]; nspredicate *p2 = [nspredicate predicatewithformat:@"subquery(links, $l, subquery($l.tags, $t, $t.name in %@).@count = %d).@count > 0", activetags, [activetags count]]; nspredicate *predicate = [nscompoundpredicate andpredicatewithsubpredicates:@[p1, p2]]; [request setpredicate:predicate];
and "trick": left hand side of predicate p2 is
subquery(links, $l, subquery($l.tags, $t, $t.name in %@).@count = %d).@count
and count of links should included in result, can create expression description predicate:
nsexpression *countexpression = [(nscomparisonpredicate *)p2 leftexpression]; nsexpressiondescription *expressiondescription = [[nsexpressiondescription alloc] init]; expressiondescription.name = @"counter"; expressiondescription.expression = countexpression; expressiondescription.expressionresulttype = nsinteger32attributetype; [request setresulttype:nsdictionaryresulttype]; [request setpropertiestofetch:@[@"name", expressiondescription]];
the resulting sqlite query quite complex. might sensible fetch links first:
nsfetchrequest *linkrequest = [nsfetchrequest fetchrequestwithentityname:@"link"]; nspredicate *linkpredicate = [nspredicate predicatewithformat:@"subquery(tags, $t, $t.name in %@).@count = %d", activetags, [activetags count]]; [linkrequest setpredicate:linkpredicate]; nsarray *activelinks = [context executefetchrequest:linkrequest error:&error];
and fetch tags in separate step, can done above code predicate p2
replace simpler subquery
nspredicate *p2 = [nspredicate predicatewithformat:@"subquery(links, $l, $l in %@).@count > 0", activelinks];
Comments
Post a Comment