Search code examples
swiftrealmrealm-listrealm-cloud

Realm Swift Filter Query Based On List Property


I need some help with a realm swift query. Here is the business context:

There are two user types:

User Type 1: Show Manager

A show manager can create shows. Below you’ll find the necessary details of a Show object. As you can see every show has a property artistResponses which is a list of ArtistResponse.

class Show: Object {
    @objc dynamic var id = UUID().uuidString
    @objc dynamic var createdDate = Date()
    @objc dynamic var showManager: ShowManager!
    @objc dynamic var venueName = ""
    @objc dynamic var city = ""
    ...
    **let artistResponses = List<ArtistResponse>()**

    override static func primaryKey() -> String? {
        return "id"
    }

    ... 
}

User Type 2: Artists

An Artist object has a citiesOfInterest property and artists on the app should only be shown shows created by show managers where the show city is in the artist’s citiesOfInterest. The artist can then view these shows and respond, which creates an ArtistResponse object and adds it to the list seen above in the Show object. Below you’ll find the necessary details of an Artist as well as an ArtistResponse object.

class Artist: Object {
    @objc dynamic var id = UUID().uuidString
    @objc dynamic var createdDate = Date()
    **let citiesOfInterest = List<String>()**
}
class ArtistResponse: Object {
    @objc dynamic var id = UUID().uuidString
    @objc dynamic var createdDate = Date()
    @objc dynamic var show: Show!
    @objc dynamic var artist: Artist!
    **@objc dynamic var available = true**

    override static func primaryKey() -> String? {
        return "id"
    }
}

The query I’m having trouble with is related to determining if it’s a new show (i.e. the artist does not have an ArtistResponse associated to the show listing themselves as available or unavailable).

Here is an example:

A show manager named Bob creates a show where the city = “Austin” An artist named Jim has citiesOfInterest = [“Austin”, “Seattle”, “San Francisco”]

Jim, the artist, comes onto the app and should see this new show listing posted by Bob, the show manager, because Jim’s citiesOfInterest contains “Austin” and the show’s city is equal to “Austin” and there is no artistResponse related to Jim.

I’ve researched and found that there are limitations with lists in Realm.

https://forum.realm.io/t/predicate-to-search-in-field-of-type-list/733 https://github.com/realm/realm-cocoa/issues/5334

Please help with this query:

Realm.objects(Show.self).filter(“somehow determine that there is not an artistResponse in the artistResponses list that is related to Jim”)

Can someone please help me with this? I hope I have provided enough explanation.


Solution

  • Let me restate the question;

    You want an artist to be able to query for all new shows in cities they are interested in where they have not yet responded.

    If that's the question, let me start with some simple sample data

    Two artists that have each have two cities if interest

    let a0 = Artist()
    a0.name = "Jim"
    a0.citiesOfInterest.append(objectsIn: ["Austin", "Memphis"])
    
    let a1 = Artist()
    a1.name = "Henry"
    a1.citiesOfInterest.append(objectsIn: ["Austin", "Memphis"])
    

    and then two shows, one in each city

    let s0 = Show()
    s0.name = "Austin Show"
    s0.city = "Austin"
    
    let s1 = Show()
    s1.name = "Memphis Show"
    s1.city = "Memphis"
    

    but artist a0 (Jim) has responded to the s0 (Austin) show

    let r0 = ArtistResponse()
    r0.show = s0
    r0.artist = a0
    r0.available = true
    
    s0.artistResponses.append(r0) //jim responded to the Austin show
    

    The result we want is that when Jim the artist logs on, he will see the Memphis show because he already responded to the Austin show.

    let realm = try! Realm()
    if let jim = realm.objects(Artist.self).filter("name == 'Jim'").first {
       let myCities = jim.citiesOfInterest
       let showResults = realm.objects(Show.self)
                              .filter("city IN %@ AND !(ANY artistResponses.artist.name == 'Jim')", myCities)
       for show in showResults {
          print(show.name)
       }              
    }
    

    And the output is

    Memphis Show
    

    We first get the Jim's cities of interest as an array, then we filter the shows that match those cities of interest but where there are no artist responses associated with Jim. This filter was based on the name but you could use the Artist id or even the Artist object itself as the comparator.