iOS Realm Filtrar objects en una list de una relación

Tengo tres objects nesteds a través de lists como esta:

class Canteen: Object { dynamic var name: String? let lines = List<Line>() } class Line: Object { dynamic var name: String? let meals = List<Meal>() } class Meal: Object { dynamic var name: String? dynamic var vegan: Bool = false } 

Obtener todos los comedores con todas las líneas y comidas no es un problema. Lo que estoy haciendo ahora es esto:

 let pnetworkingicate = NSPnetworkingicate(format: "name == %@", selectedCanteenType.rawValue) canteens = realm.objects(Canteen).filter(pnetworkingicate) 

Pero ahora solo necesito las comidas que son veganas. Así que estoy buscando la cantina seleccionada con todas las líneas, pero solo con las comidas que son veganas. ¿Es posible en el reino, filtrar lists en objects recuperados?

Realm no tiene ningún tipo de concepto de una vista filtrada en profundidad, por lo que no puede tener una Results<Canteen> que restrinja la List contenida en los objects relacionados a las comidas veganas.

Hay varias cosas similares que puedes hacer. Puede agregar properties de relación inversa y luego consultar objects de Meal lugar:

 class Canteen: Object { dynamic var name: String? let lines = List<Line>() } class Line: Object { dynamic var name: String? let meals = List<Meal>() let canteens = LinkingObjects(fromType: Canteen.self, property: "lines") } class Meal: Object { dynamic var name: String? dynamic var vegan: Bool = false let lines = LinkingObjects(fromType: Line.self, property: "meals") } let meals = realm.objects(Meal).filter("vegan = true AND ANY lines.canteens.name = %@", selectedCanteenType.rawValue) 

(O mejor dicho, podrá una vez que el Realm 0.102.1 esté fuera, actualmente se bloquea).

Si solo necesita repetir las comidas pero necesita hacerlo desde la cantina, puede hacer lo siguiente:

 let canteens = realm.objects(Canteen).filter("name = %@ AND ANY lines.meals.vegan = true", selectedCanteenType.rawValue) for canteen in canteens { for line in canteen.lines.filter("ANY meals.vegan = true") { for meal in line.meals.filter("vegan = true") { // do something with your vegan meal } } } 

Desafortunadamente, esto tiene cierta duplicación debido a la necesidad de repetir el filter para cada nivel de las references.

Prueba esto:

 let pnetworkingicate = NSPnetworkingicate(format: "name == %@", "") var canteens: [Canteen] = realm.objects(Canteen).filter(pnetworkingicate).map { can in // Iterate through all the Canteens let lines: [Line] = can.lines.map { (line: Line) in // Iterate through all the lines in each canteene // Filter all the Meals that are NOT vegan let meals = line.meals.filter { $0.vegan == true } line.meals = List<Meal>(meals) return line } can.lines = List<Line>(lines) return can } 

Realm le permite usar funciones como parámetro para el filtrado. Entonces, esta es mi solución que estoy usando actualmente.

Las dos funciones de filter:

 func vegetarianFilter(_ meal: Meal) -> Bool { if showVegetarianOnly { if(meal.veg || meal.vegan){ return true } return false } return true } func filterEmptyLines(_ line: Line) -> Bool { if(line.meals.filter(vegetarianFilter).count > 0){ return true } return false } 

Las funciones filtran todas las comidas que no son vegetarianas o veganas cuando el usuario ha seleccionado showVegetarianOnly = true . También filtra todas las líneas que no tienen comida (nada es vegetariano o vegetariano).

Funciones más importantes de TableView:

  override func numberOfSections(in tableView: UITableView) -> Int { return canteenDay?.lines.filter(filterEmptyLines).count ?? 0 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return canteenDay?.lines.filter(filterEmptyLines)[section].meals.filter(vegetarianFilter).count ?? 0 } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell() let meal = canteenDay!.lines.filter(filterEmptyLines)[indexPath.section].meals.filter(vegetarianFilter)[indexPath.row] cell.textLabel?.text = meal.meal return cell }