It does not respect `&&` operator when filtering a list of embedded objects

It seem realm does not respect && operator when filtering a list of embedded objects.

In this specific case it filter correctly key == "rooms" but second statement value == 4 seems to be ignored , once results brings rows with values different from 4 .

class Property: Object, ObjectKeyIdentifiable {
    @Persisted(primaryKey: true) var _id: ObjectId
    @Persisted var name: String
    @Persisted var specs: List<PropertySpec>

     // ...
}
class PropertySpec: EmbeddedObject, ObjectKeyIdentifiable {
    @Persisted var key: String
    @Persisted var value: Double?

    //  ...
}
struct SearchResultView: View {
    @ObservedResults(Property.self) var properties
   
     var filteredProperties: Slice<Results<Property>> {
        var results = properties
            .where {
              // It ignores && operator
              // Actually it seems to consider any value == 4, not only "rooms"
                $0.specs.key == "rooms" && $0.specs.value == 4     
            }

         return results.prefix(50)
     }

}



I am suspecting it will consider any spec.value with 4 .

Sample Data:

  • Property 1
    • specs:
      • rooms = 4
      • bathrooms = 3
  • Property 2
    • specs:
      • rooms = 3
      • bathrooms = 8
  • Property 3
    • specs:
      • rooms = 6
      • bathrooms = 4 // <---- suspect here!

I also tried this, but it does not work. The list will be empty.

.where {
    $0.specs.contains(PropertySpec(key: "rooms", value: 4))
}

A question (to which the answer may be obvious).

Realm is more type safe with the .where clause, however that implementation uses a dynamic lookup which may be related to your issue (or may not)

“because we use dynamic lookup it means you can use any property name which may not be declared in the object”

The point of adding the .where was to make querying type safe. By using key and value that kinda goes back the other not-type-safe direction.

Is there a reason you don’t just use this to query for properties that only have 4 rooms?

let results = realm.objects(Property.self).where { $0.specs.rooms == 4 }

@Jay I am looking for something dynamic.

Because each Property can have different Specifications. In that case there are dozen of specs to be chosen when creating a new Property

So customers can look for : What Property has 4 rooms and more than 2 bathrooms ?


Anyway, for future reference, here is my workaround. I don’t think is intuitive, but it works.

.where{
  // Property with 4 rooms
  ($0.specs.key == "rooms" && $0.specs.value == 4).count == 1
}
.where{
  // Property with more than 2 bathrooms
  ($0.specs.key == "bathrooms" && $0.specs.value >= 2).count == 1
}

Ah. Interesting - yeah, I can see where that would be more dynamic.

Obviously there are some standard specs; rooms, bathrooms etc that could just be model properties rooms and bathrooms in the model which leads to;

let results = realm.objects(Property.self).where { $0.specs.rooms == 4 && $0.specs.bathrooms > 2 }

I still think the .key property is causing the issue but one other thing to consider (which you may have already considered) is to leverage the Realm Map property as it really seems well suited for this use case and isn’t a workaround.

So your Model would look like this

class Property: Object {
    @Persisted var name: String
    @Persisted var propertySpecs: Map<String, Int>
}

And then the Map property could contain any spec needed rooms, bathrooms, etc and could be queried like this

let results = realm.objects(Property.self).where { $0.propertySpecs["rooms"] == 4 && $0.propertySpecs["bathrooms"] > 2 }

Just a thought.

@Jay Thanks for pointing another alternative :slight_smile: