Существует ли NSPredicate для фильтрации моделей с отношением «один ко многим» (фильтровать множество)?

#ios #swift #core-data #nspredicate

#iOS #swift #core-data #nspredicate

Вопрос:

У меня есть две модели: альбом и песня, альбом содержит N песен, но песня содержит только 1 альбом. Я пытаюсь создать конкретный фильтр, но я не смог найти NSPredicate, который дает мне ожидаемые результаты.

Я создал обе модели в CoreData:

quot;Альбомquot;
quot;Песняquot;

Итак, я создал несколько объектов:

 let song1 = Song(context: context)
song1.name = "I Love You"
song1.composer = "Ana"

let song2 = Song(context: context)
song2.name = "Hello And Goodbye"
song2.composer = "Ben"

let song3 = Song(context: context)
song3.name = "I Miss You"
song3.composer = "Marie"

let song4 = Song(context: context)
song4.name = "Lonely"
song4.composer = "Ana"

let album = Album(context: context)
album.name = "Love Songs 1"
let set = NSSet(array: [song1, song2, song3])
album.addToSong(set)

let album2 = Album(context: context)
album2.name = "Love Songs 2"
let set2 = NSSet(array: [song4])
album2.addToSong(set2)

  

Итак, я хотел бы выполнить этот фильтр:

Получить альбомы, где Ana является композитором, А название песни содержит «n»

Я извлекаю модель Albums с этим предикатом:

 let composerPredicate = NSPredicate(format: "ANY song.composer = %@", "Ana")
let songPredicate = NSPredicate(format: "ANY song.name contains %@", "n")

let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [composerPredicate, songPredicate])
  

Но в полученных результатах я получил оба альбома, но я хотел бы вернуть мне только «Песни о любви 2».

Вы знаете, как я мог бы это сделать?

ПРАВКА1: Я хотел бы найти решение, которое не использует никаких карт, фильтров или циклов (если это возможно), потому что это напрямую влияет на производительность, потому что я имею дело с большим количеством данных.

Комментарии:

1. Song2 имеет n в названии, поэтому оба альбома должны быть возвращены, поскольку вы используете ANY

2. Я не могу удалить ANY, потому что он выходит из строя с этой ошибкой: «Завершение работы приложения из-за неперехваченного исключения ‘NSInvalidArgumentException’, причина: ‘ключ to-many здесь не разрешен'»

Ответ №1:

Вам нужно использовать ПОДЗАПРОС, потому что вы хотите включить альбом, только если в нем есть песня, соответствующая обоим критериям. (Ваш составной предикат будет включать альбом, в котором есть одна песня, соответствующая первому критерию, и другая песня, соответствующая второму критерию).

 let predicate = NSPredicate(format: "SUBQUERY(song, $S, $S.composer == %@ AND $S.name contains %@).@count > 0", “Ana”, "n")
  

Комментарии:

1. Это отлично сработало для моей проблемы! Большое спасибо! Я никогда раньше не использовал подзапросы, поэтому не знал, что это может быть решением.

2. Вы знаете, как я мог бы отсортировать альбомы по названию песни? Также используются предикаты или sortDescriptors.

3. Вы не можете сортировать альбомы по названию песни, потому что в каждом альбоме много песен. Вы можете сортировать только по атрибуту или отношению «к одному».