Reputation: 457
I have two entities in realm Product and ProductType. Product has one to many relation with Product Type.
Product entity one to many
import Foundation
import RealmSwift
class Product: Object{
dynamic var productName = ""
let productTypeList = List<ProductType>()
}
ProductType entity
import Foundation
import RealmSwift
class ProductType: Object{
dynamic var typeName: String = ""
dynamic var typeLogoUrl: String = ""
}
My goal is select all products, which contains ProductType typeName, for example "Electronics". I can do it easily, if there were one to one relationship like this
Product entity one to one
import Foundation
import RealmSwift
class Product:Object{
dynamic var productName = ""
dynamic var productType : ProductType?
}
Query example
let realm = try! Realm()
let productTypeName = "Electronics"
let predicate = NSPredicate(format: "productType.typeName == %@", productTypeName)
let rmProducts = realm.objects(Product.self).filter(predicate)
Any ideas how to make query with one to many version of Product class?
Upvotes: 3
Views: 2517
Reputation: 54805
You can use a subquery and check that the count of the productTypes in the list matching the name is bigger than 0.
let rmProducts = realm.objects(Product.self).filter("SUBQUERY(productTypeList, $type, $type.typeName == %@).@count>0",productTypeName)
I have run the query on the following test set and got the expected results:
class Product:Object{
dynamic var productName = ""
var productTypeList = List<ProductType>()
}
class ProductType : Object{
dynamic var typeName: String = ""
dynamic var typeLogoUrl: String = ""
}
let types = [ProductType(value: ["typeName":"Electronics","typeLogoUrl":"url"]),ProductType(value: ["typeName":"a","typeLogoUrl":"url"]),ProductType(value: ["typeName":"Electronics","typeLogoUrl":"a"]),ProductType(value: ["typeName":"b","typeLogoUrl":"url"])]
let prod1 = Product()
prod1.productName = "a"
prod1.productTypeList = List([types[0],types[1]])
let prod2 = Product()
prod2.productName = "b"
prod2.productTypeList = List([types[3],types[1]])
let prod3 = Product()
prod3.productName = "c"
prod3.productTypeList = List([types[2],types[1]])
var prod4 = Product()
prod4.productName = "d"
prod4.productTypeList = List([types[1]])
try! realm.write {
realm.add(types)
realm.add([prod1,prod2,prod3,prod4])
}
let productTypeName = "Electronics"
let predicate = NSPredicate(format: "productType.typeName == %@", productTypeName)
let rmProducts = realm.objects(Product.self).filter("SUBQUERY(productTypeList, $type, $type.typeName == %@).@count>0",productTypeName)
print(rmProducts) //rmProducts contains prod1 and prod3 as expected
Upvotes: 3
Reputation: 18308
For a simple query like this, you want the ANY
modifier:
realm.objects(Product.self).filter("ANY productTypeList.typeName == %@", productTypeName)
A SUBQUERY
, as suggested in another answer, is only necessary if you need more than one criteria on each sub-object to match. For instance, if you wanted to find Products
that have items of a given type whose URLs start with https://
you would use a SUBQUERY
:
realm.objects(Product.self).filter("SUBQUERY(productTypeList, $type, $type.typeName == %@ AND $type.typeLogoUrl BEGINSWITH 'https://').@count > 0", productTypeName)
Upvotes: 3