【问题标题】:How to use the "ALL" aggregate operation in a NSPredicate to filter a CoreData-based collection如何在 NSPredicate 中使用“ALL”聚合操作来过滤基于 CoreData 的集合
【发布时间】:2011-07-15 05:28:44
【问题描述】:

基于下面的数据模型

根据用户输入,我创建了一个名为 selectedTags 的实体标签的 managedObjects 的 NSSet。


我的问题:

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

...这将返回 any 条目,其中至少有一个在 selectedTags 集中的 entryTag。

我想要一些类似的东西:

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

...注意唯一的变化是“ANY”到“ALL”。这说明了我想要的,但不起作用。

制定我期望的结果:

我正在寻找一种解决方案,它只返回 entryTags 都在 selectedTags 列表中的条目(但同时,如果可能,不一定反过来)。

进一步说明:

(标签)妈妈
(tag)爸爸
(tag)礼物

(条目)她是个女人.....(标签)妈妈
(entry)he is a he.......(tag)爸爸
(条目)给妈妈的礼物......(标签:)妈妈,礼物
(entry)给爸爸的礼物.....(tags:)爸爸,礼物

如果 selectedTags 包含“mom”和“gifts”,则条目“gifts for dad”将显示,因为它有标签“gifts”。我宁愿让它不显示:)

【问题讨论】:

  • 澄清:selectedTags 是另一个实体还是Entries 的属性或关系? entryTags 是属性还是关系?
  • 我一直在查看您的答案,并希望您能对此发表意见:D 我更新了问题。

标签: objective-c ios core-data nspredicate


【解决方案1】:

到目前为止,这是肯定的答案:

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

B-E-A-U-T-I-F-U-L.

感谢戴夫·德隆。

【讨论】:

  • 我不确定 selectedTags 是否必须是 NSArray 或 NSSet,所以我两种方式都进行了测试,任何一种都可以。
  • 这正是我所需要的,谢谢! (现在我也知道子查询了)
【解决方案2】:

使用复合谓词怎么样?据我了解,您希望返回与标签列表匹配的所有条目,而不仅仅是其中的任何一个。一种方法是为每个标签创建一个谓词,然后使用复合谓词将它们 AND 在一起。

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];

这应该实现你想要的。然后根据您的请求设置此谓词。

【讨论】:

  • 我不明白如何使用此代码。需要详细说明吗?我想返回所有 Entry 对象,其中 Entry.entryTags 包含 selectedTags 中的所有 Tag 对象。
  • 基本上你想返回与你拥有的标签列表匹配的所有条目。因此,您为要匹配的每个标签编写一个谓词。因此,您的谓词类似于返回具有与此标签名称匹配的标签的任何条目。然后你将每个标签的所有这些谓词加在一起,你会得到所有结果的交集,即在 selectedTags 中具有所有标签的条目。我在上面编辑了我的答案以使用您的变量名称。
  • 非常干净的解决方案。对于普通的 obj c 开发人员来说,比 SUBQUERY 谓词更具可读性。
  • 这个答案对我来说效果很好,据我所知,我的需求与问题中的解释相匹配。
【解决方案3】:

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

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

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

既然你已经有了你想要的Tag对象,要找到候选相关的Entity对象,你只需要走Tag.taggedEntries关系。然后,您必须找到所有 Entity 对象集合的交集,以仅找到与 every 选择的 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"]];
    }
}

(注意:我没有对此进行测试,但它应该可以工作。)

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

【讨论】:

    【解决方案4】:

    我意识到我可以在这里为我之前获得的指导回馈一些东西。通过使用 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 数组中提供的所有对象上键 key 的所有值(在我的情况下为对象)。

    这段代码只是...味道不错,不是吗?

    【讨论】:

      【解决方案5】:

      最简单的方法:

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

      您不需要 ALL 子句。它也记录在这里:

      Predicate Programming guide

      正如您在这篇文章中看到的那样,用户成功地做到了(阅读原始问题的 cmets)

      NSPredicate iPhone 3.2 SDK Core Data “IN clause”...

      【讨论】:

        猜你喜欢
        • 2014-12-19
        • 1970-01-01
        • 2013-01-06
        • 1970-01-01
        • 1970-01-01
        • 2021-08-17
        • 2020-06-22
        • 2022-01-16
        • 1970-01-01
        相关资源
        最近更新 更多