2
votes

I have two models: Album and Song, the album contains N songs, but the song contains only 1 album. I'm trying to make a specific filter, but I couldn't find a NSPredicate that gives me the results I expect.

I created both models on CoreData:

"Album""Song"

So I created some objects:

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)

So, I would like to do this filter:

Get albums where Ana is the composer AND the song's name contains "n"

I'm fetching the Albums model with this predicate:

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

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

But on fetched results I got both albums, but I would like to return me only "Love Songs 2".

Do you know how could I do this?

EDIT1: I would like to find a solution that don't uses any maps, filters or loops (if it is possible), because it impacts directly on performance, because I deal with a lot of data.

1
Song2 has a n in the title so both albums should be returned since you use ANY – Joakim Danielson
I can't remove the ANY because it crashes with this error: "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'to-many key not allowed here'" – Anne Kariny Silva Freitas

1 Answers

3
votes

You need to use SUBQUERY because you want to include an album only if it has a song that matches both criteria. (Your compound predicate will include an album that has one song that matches the first criterion, and a different song that matches the second criterion).

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