Home > Blockchain >  How to get Realm Objects by ID only?
How to get Realm Objects by ID only?

Time:11-25

I set up a Realm model (in Swift) with a children relationship:

import Foundation
import RealmSwift

class MyObject1: RealmSwift.Object, RealmSwift.ObjectKeyIdentifiable {
    @Persisted(primaryKey: true) var _id: RealmSwift.ObjectId
    @Persisted var childrenIDs = RealmSwift.List<String>()
}

I added the relationship as a RealmSwift.List of Strings, because I intent to create other model classes, each with an ID, that can be added as children. In other words, the children might not be of a single type/class. For example:

import Foundation
import RealmSwift

class MyObject2: RealmSwift.Object, RealmSwift.ObjectKeyIdentifiable {
    @Persisted(primaryKey: true) var _id: RealmSwift.ObjectId
    @Persisted var title: String
}

Now at some point, I have to fetch all the children by their ID, for example to show them in a list. But I do not know how. I know the realm.objects(Class.self).filter but this expects a single class type. So my question is, how can I fetch objects from a Realm only by their ID (ie without their class/type)?

CodePudding user response:

As mentioned in a comment, ObjectId's are generic and have no correlation to the object class they are tied to. So you can't do exactly what you want.

But... there are options.

TL;DR

  1. create another object with properties to hold the id and the object type, defined by an enum or

  2. Use AnyRealmValue to store the objects themselves

Long answers:

Long answer #1

Create a class to store the id and type. Suppose we have a database that stores wine grape types; some are white and some are red but you want to store them all in the same list. Let me set up an example

enum GrapeTypesEnum: String, PersistableEnum {
    case white
    case red
}

class Grape: Object {
   @Persisted(primaryKey: true) var _id: RealmSwift.ObjectId
   @Persisted var grape_name = ""
   @Persisted var grape_type: GrapeTypesEnum
}

class GrapeObjects: Object { //contains the grape id string & grape type
   @Persisted var child_id = ""
   @Persisted var child_type: GrapeTypesEnum
}

so then the model would be

class MyObject1: RealmSwift.Object {
    @Persisted(primaryKey: true) var _id: RealmSwift.ObjectId
    @Persisted var childGrapes = RealmSwift.List<GrapeObjects>()
}

You could then create a couple of grapes

let whiteGrape = Grape()
whiteGrape.name = "Chenin Blanc"
whiteGrape.grape_type = .white

let redGrape = Grape()
redGrape.name = "Cabernet Franc"
redGrape.grape_type = .red

let grape0 = GrapeObjects()
grape0.grape_id = whiteGrape._id.stringValue()
grape0.grape_type = whiteGrape.grape_type

let grape1 = GrapeObjects()
grape1.grape_id = redGrape._id.stringValue()
grape1.grape_type = redGrape.grape_type

then finally store those objects in your class. Those can then be sorted, filtered and you will know which ID goes with what type of object

let anObject = MyObject1()
anObject.childGrapes.append(objectsIn: [grape0, grape1])

Long answer #2

Another option is to not store the objectID string but store the actual objects by leveraging AnyRealmValue

class MyClass: Object {
   @Persisted var myList = List<AnyRealmValue>()
}

let red = WhiteGrape()
let white = RedGrape()

let obj0: AnyRealmValue = .object(red) //both of these are objects, 
let obj1: AnyRealmValue = .object(white) //  even through they are different objects

let m = MyClass()
m.myGrapeList.append(obj0)
m.myGrapeList.append(obj1)

Then you can take action based on the the objects type

for grape in m.myGrapeList {
   if let white = grape.object(WhiteGrape.self) {
      print("is a white grape")
   } else if let red = grape.object(RedGrape.self) {
      print("is a red grape")
   }
}
  • Related