anonymous
anonymous

Reputation: 1330

Multiple Realm queries for different Objects

I want to create an entire database search that returns an object of type Results<A>. I have a class A that inherits from a Realm Object and then a lot of other classes that inherit from that subclass. Something like this:

class A: Object {}
protocol Z {}
class B: A, Z {}
class C: A, Z {}
class D: A, Z {}
...

Now I want to query different classes at the same time and I'm doing something like this:

private func getResults<T: A>(withTypes types: [T.Type]) {
  for type in types {
    let foundIds = getRealm().objects(type).filter(aPredicate)
    ids.append(contentsOf: foundIds)
  }

  // Do something with all those ids
}

And I'm calling it like this:

getResults(withTypes: [B.self, C.self, D.self])

The problem is that Realm does not like polymorphism and as soon as I add more than one class type inside the array when calling the function it crashes because the inferred type of the array is A.self instead of the individual element in each position of the array. The filtering is done by using a Z protocol variable that A does not conform -and it shouldn't- but the rest of object do conform it. So this works:

getResults(withTypes: [C.self])

or this:

getResults(withTypes: [D.self])

Because the inferred type of the Array is C.self or D.self and not the generic inferred A.self.

I want to point out that in the database there is not any A object, it's just the superclass of all the other objects.

How can I create that multiple search?

I've thought that I could create a kind of searchable object and query it but the database that I manage is huge and I do not know if that would create a big impact on the system's performance.

Thanks in advance!

Upvotes: 3

Views: 1914

Answers (1)

Kalzem
Kalzem

Reputation: 7501

In your query, if you are only interested in getting the ids and appending them to an Array, you can map them ids.append(contentsOf: foundIds.map({ $0.idFromZProtocol })). But this will disable the lazy loading of Realm because all objects will be visited.

What you can also do is doing the other way:

  • Let's say A is Animal, B is Dog, C is Bird, D is cat.
  • You are looking for all the green animals.

You can have

Animal
@objc dynamic var dog: Dog?
@objc dynamic var bird: Bird?
@objc dynamic var cat: Cat?

Bird, Cat, Dog
@objc dynamic var color: String
@objc dynamic var legNumber: Int

let predicate = "dog.color == Green || bird.color == Green || cat.color == Green"
getRealm().objects(Animal.self).filter(predicate)

And you can have a processed variable on Animal to know if it's a cat or dog or bird by checking which variable isn't nil. You can also assign your Z protocol to Dog, Cat and Bird in order to do Animal.color instead of guessing Animal.dog?.color or Animal.cat?.color etc

With this approach, you can keep the lazy loading feature of Realm which is nice if you have a very big Realm file.

Upvotes: 1

Related Questions