Let's say I have a Realm schema where I have a parent class and kids underneath it in a List
. Like this:
class Parent: Object{
@objc dynamic var name = ""
let kids = List<Kid>()
}
class Kid: Object{
@objc dynamic var name = ""
}
Let's say that, over time, whenever a Kid
was deleted, it was only removed from the Parent
object and wasn't deleted from the Realm:
let realm = try! Realm()
let parent = realm.objects(Parent.self)
realm.beginWrite()
for kid in parent.kids{
if let index = parent.kids.index(of: kid){
parent.kids.remove(at: index)
}
}
try! realm.commitWrite()
I know I can delete the kids
from the Realm in the same write transaction as the removal from the parent
:
let kids = parent.kids
realm.delete(kids)
...but I have reasons not to.
Is there a way to query the Realm database for all kids
that don't belong to a parent
? For example, if you were to open my Realm, you could see 100
kid
objects, but if you look at the parents, only 5
of the kid
objects are actually attached to a parent
object.
I have a special use case of Realm where I don't actually want to delete the child List
items unless I know they don't have a parent. Is it possible to query a Realm for all parentless kid
s?
Unless you use LinkingObjects there's no way to query realm for kids without parents directly. If it's not too late to change your data model then I would suggest using them.
class Parent: Object{
@objc dynamic var name = ""
let kids = List<Kid>()
}
class Kid: Object{
@objc dynamic var name = ""
let parents = LinkingObjects(fromType: Parent.self, property: "kids")
}
When you add a Kid
to Parent.kids
realm automatically handles the Kid.parents
relationship for you. When you delete a Parent
, Kid.parents
will be empty (assuming the Kid
only had one Parent
). The great thing about LinkingObjects
is that you can incorporate them into your queries. So to find all Kid
objects without parents the query would be:
func fetchKidsWithoutParents1() -> Results<Kid> {
let realm = try! Realm()
return realm.objects(Kid.self).filter("parents.@count == 0")
}
If you don't use LinkingObjects
, you have to query for all Kid
objects and all Parent
objects and see if the Kid
exists in any Parent.kids
List
. There are two downsides to this approach. The first is that that all Kid
objects will be loaded into memory as you filter them manually. The other is that you can't take advantage of realm notifications because the resulting kids would not be stored in a realm Result
object. Note that the following example assumes that there are no two Kid
objects with the same name:
func fetchKidsWithoutParents2() -> [Kid] {
let realm = try! Realm()
let kids = realm.objects(Kid.self)
let parents = realm.objects(Parent.self)
return kids.filter { kid in
parents.filter("SUBQUERY(kids, $kid, $kid.name == %@).@count > 0", kid.name).count == 0
}
}