Подтвердить что ты не робот

Как использовать агрегированную операцию "ALL" в NSPredicate для фильтрации коллекции на основе CoreData

На основе модели данных ниже

dataModel

И на основе ввода пользователем я создаю NSSet управляемых объектов объекта тега, называемых selectedTags.


Моя проблема:

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

... это приведет к возврату любой записи с по крайней мере одним элементом ввода, который находится в выбранном наборе тагов.

Я хочу что-то вроде:

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

... Обратите внимание, что единственным изменением является "ЛЮБОЙ" для "ВСЕ". Это иллюстрирует то, что я хочу, но не работает.

Чтобы сформулировать результат, я ожидаю:

Я ищу решение, которое будет возвращать только те записи, которые entryTags находятся в списке selectedTags (но в то же время, если это возможно, не обязательно наоборот).

Для дополнительной иллюстрации:

(тег) мама
(Тег) папа
(тег) Подарки

(запись) она она..... (тег) мама
(вход), он является............ (тег) папа
(вход) подарки для мамы... (метки:) мама, подарки
(вход) подарки для папы..... (теги:) папа, подарки

Если selectedTags содержит "mom" и "gifts", тогда появится запись "подарки для папы", так как у нее есть тег "подарки". Я бы предпочел, чтобы он не показывал:)

4b9b3361

Ответ 1

Это определенный ответ:

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

В-Е-А-У-Т-I-F-U-L.

Благодаря Дейву ДеЛонгу.

Ответ 2

Как насчет использования сложного предиката? Насколько я понимаю, вы хотите вернуть все записи, которые соответствуют списку тегов, а не только любому из них. Один из подходов заключался бы в создании предиката для каждого тега, затем И их вместе с использованием сложного предиката.

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

Это должно достичь желаемого. Затем просто установите этот предикат по вашему запросу.

Ответ 3

Вы не можете делать то, что хотите, с помощью предиката.

Операторы ANY и ALL применяются к проверяемой сущности (в данном случае Entry), а не к содержимому коллекции (selectedTags). Любой оператор возвращает объект Entry, который соответствует любому одному элементу коллекции. Оператор ANY вернет первое совпадение, которое он найдет, пока оператор ALL вернет все совпадения. В любом случае они не возвращают запись, которая соответствует каждому элементу в предоставленной коллекции.

(Также похоже, что вы пытаетесь использовать фактические объекты Tag в selectedTags. Это, скорее всего, не сработает либо потому, что объект сравнивается с классами без специальных методов сравнения, как правило, терпит неудачу. сравнить атрибуты в предикатах.)

Поскольку у вас уже есть объекты Tag, которые вы хотите, чтобы найти связанные с кандидатом объекты Entity, вам просто нужно пройти связь Tag.taggedEntries. Затем вам нужно найти пересечение всех наборов объекта Entity, чтобы найти только те объекты Entity, которые связаны с каждым выбранным Tag bject. Поскольку нет оператора пересечений, вам нужен цикл.

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

Если не сразу видно, что делает этот код:

Он собирает все значения (в моих объектах) для ключа key для всех объектов, представленных в массиве objects.

Этот код просто... на вкус хороший, не так ли?

Ответ 5

Самый простой способ сделать это:

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

Вам не нужно предложение ALL. Это также описано здесь:

Руководство по программированию предикатов

И как вы можете видеть в этом сообщении, пользователь делает это успешно (прочитайте комментарии к исходному вопросу)

NSPredicate iPhone 3.2 Основные данные SDK "IN clause" ...