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 String
s, 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
create another object with properties to hold the id and the object type, defined by an enum or
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")
}
}