Reputation: 5710
Background / context:
In RealmSwift, if I have an object that has a List
of sub-objects, I can find all objects where any sub-objects satisfy some criteria by using ANY
in my predicate.
For example, say I have the following schema:
import RealmSwift
class Parent: Object {
@objc dynamic var name = "" // Used to identify query results
var children = List<Child>()
}
class Child: Object {
@objc dynamic var x = 0
@objc dynamic var y = 0
}
And say I create and persist a parent like this:
let parent = Parent()
let child = Child()
child.x = 1
parent.children.append(child)
let realm = try! Realm()
try! realm.write { realm.add(parent) }
If I want to find all parents with children where x is 1, I can simply do a query like this:
let result = realm
.objects(Parent.self)
.filter(NSPredicate(format: "ANY children.x == 1"))
Problem:
But now, if I want to find all parents with children where x is 1 and y is 2, I don't understand how to write the query.
Say I create and persist two parents like this:
// Parent 1 should satisfy the query:
// It has 1 child that meets all criteria.
let parent1 = Parent()
parent1.name = "Parent 1"
let childOfParent1 = Child()
childOfParent1.x = 1
childOfParent1.y = 2
parent1.children.append(childOfParent1)
// Parent 2 should not satisfy the query:
// It has 2 children, each of which only partially meets the criteria.
let parent2 = Parent()
parent2.name = "Parent 2"
let child1OfParent2 = Child()
child1OfParent2.x = 1
child1OfParent2.y = -100 // Does not match criteria
parent2.children.append(child1OfParent2)
let child2OfParent2 = Child()
child2OfParent2.x = -100 // Does not match criteria
child2OfParent2.y = 2
parent2.children.append(child2OfParent2)
let realm = try! Realm()
try! realm.write {
realm.add(parent1)
realm.add(parent2)
}
Now, I can try to find only parents with children where x is 1 and y is 2 like this:
let results = realm
.objects(Parent.self)
.filter(NSPredicate(format: "ANY children.x == 1 && ANY children.y == 2"))
results.forEach { print($0.name) }
// This prints:
// Parent 1
// Parent 2
I want the query to return only Parent 1, but it returns both parents. The query matches any parents with children where x is 1, and also with children where y is 2, even if those are not the same children.
How would I rewrite my query so that it only matches parent 1?
Upvotes: 0
Views: 822
Reputation: 5710
Ah, found it. The key is to use SUBQUERY
.
A subquery is formatted as SUBQUERY(collection, itemName, query)
, and returns all sub-objects matching the query. So to find parents with children matching the query, you need to check the count of the resulting sub-objects.
In my example, the query would be:
let results = realm
.objects(Parent.self)
.filter(NSPredicate(format: "SUBQUERY(children, $child, $child.x == 1 && $child.y == 2).@count > 0"))
I.e fetch all Parent
objects with more than 0 children matching the predicate x == 1 && y == 2
.
Upvotes: 3