如何在NSPredicate中使用“ALL”聚合操作来过滤基于CoreData的集合

基于下面的数据模型

数据模型

并基于用户input,我创build了一个名为selectedTags的实体标记的managedObjects的NSSet。


我的问题:

[NSPredicate predicateWithFormat:@"ANY entryTags IN %@", selectedTags]; 

…这将返回至less有一个EntryTag在SelectedTags集中的任何条目。

我想要的东西是:

 [NSPredicate predicateWithFormat:@"ALL entryTags IN %@", selectedTags]; 

…注意唯一的变化是“任何”到“全部”。 这说明了我想要的,但不起作用。

为了制定我期望的结果:

我正在寻找一个解决scheme,将只返回入口的入口标签都在selectedTags列表(但在同一时间,如果可能的话,不一定是相反的方式)。

为了进一步说明:

(标签)的妈妈
(标签)爸爸
(标签)礼品

(进入)她是她…..(标签)妈妈
(进入)他是一个他……..(标签)爸爸
(进入)礼物给妈妈…(标签:)妈妈,礼物
(入门)爸爸的礼物…..(标签:)爸爸,礼物

如果selectedTags包含“妈妈”和“礼物”,那么“爸爸的礼物”将会出现,因为它有“礼物”的标签。 我宁愿它不显示:)

这是迄今为止确定的答案:

 [NSPredicate predicateWithFormat:@"SUBQUERY(entryTags, $tag, $tag IN %@).@count = %d", selectedTags, [selectedTags count]]; 

美丽。

感谢Dave DeLong。

如何使用复合谓词? 据我所知,你想返回所有条目匹配的标签列表不只是其中的任何一个。 一种方法是为每个标签创build一个谓词,然后使用复合谓词将它们联系起来。

 NSMutableArray *predicates = [[NSMutableArray alloc] init]; for (Tag *tag in selectedTags) { [predicates addObject:[NSPredicate predicateWithFormat:@"ANY entryTags.tagName MATCHES %@", tag.tagName]]; } NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates]; 

这应该达到你想要的。 然后,只需在请求中设置谓词。

你不能用谓词做你想要的。

ANYALL运算符适用于正在testing的实体(在本例中为Entry ),而不适用于集合( selectedTags )的内容。 任何一个操作符都将返回一个与该集合中任何单个元素相匹配的Entry对象。 ANY运算符将返回find的第一个匹配项,而ALL运算符将返回所有匹配项。 在任何情况下,他们都不会返回与提供的集合中的每个元素相匹配的条目。

(它也看起来像你正在试图在selectedTags使用实际的Tag对象,这很可能不起作用,因为没有专用比较方法的对象比较通常会失败,它也很慢,你需要比较谓词中的属性。

既然你已经有了你想要的Tag对象,要find与候选相关的Entity对象,你只需要走Tag.taggedEntries关系。 然后,您必须find所有的Entity对象集合的交集,才能find与每个选定的Tag对象相关的Entity对象。 由于没有相交的集合运算符,所以需要一个循环。

 if ([selectedEntries count]>=2) { NSMutableSet *intersectEntries=[[NSMutableSet alloc] initWithCapacity:1]; for (int i=1; i<[selectedTags count]; i++) { if ([intersectEntries count]==0) { [intersectEntries unionSet:[[selectedEntries objectAtIndex:(i-1)] valueForKey:@"taggedEntries"]]; } [intersectEntries intersectSet:[[selectedEntries objectAtIndex:i] valueForKey:@"taggedEntries"]]; } } 

(注:我没有testing这个,但它应该工作。)

现在intersectEntries应该只包含那些与每个选定标签相关的Entry对象。

我意识到我可以回到这里来获得我以前得到的指导。 通过使用TechZen提供的代码,我能够提出以下几点 – 对我来说,高度重视的一段代码:

 - (NSArray *)unionSetOfObjectsForObjects:(NSArray *)objects { NSMutableSet *unionSetOfObjects = [NSMutableSet set]; if (objects.count) [unionSetOfObjects unionSet:[[objects objectAtIndex:0] valueForKey:@"key"]]; //unionSetOfObjects = [[objects objectAtIndex:0] valueForKey:@"key"]; if (objects.count > 1) for (id object in objects) [unionSetOfObjects intersectSet:[object valueForKey:@"key"]]; return unionSetOfObjects.allObjects; } 

如果这个代码不是很明显的话:

它收集所有objects数组中提供的所有对象上的键值(在我的大小写对象中)。

这个代码只是…味道不错,不是吗?

最简单的方法来做到这一点:

 [NSPredicate predicateWithFormat:@"entryTags IN %@", selectedTags]; 

你不需要ALL子句。 这也logging在这里:

谓词编程指南

正如你可以在这篇文章中看到的,用户成功地做到了这一点(阅读原始问题的评论)

NSPredicate iPhone 3.2 SDK核心数据“IN子句”…