web-dev-qa-db-ja.com

関係のリスト内のiOSレルムフィルターオブジェクト

このようなリストを介してネストされた3つのオブジェクトがあります。

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
}

すべてのラインと食事ですべての食堂を手に入れることは問題ありません。今私がやっているのはこれです:

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

しかし、今はビーガンの食事だけが必要です。だから、すべてのラインで選択された食堂を手に入れたいと思っていますが、ビーガンの食事でのみです。これは、取得されたオブジェクトのリストをフィルタリングするために、レルムで可能ですか?

14
Daniel Storch

レルムには、ディープフィルター処理されたビューという概念がありません。したがって、Results<Canteen>これは、関連オブジェクトに含まれるListsをビーガンミールに制限します。

同様のことができることがいくつかあります。逆関係のプロパティを追加してから、代わりにMealオブジェクトをクエリできます。

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)

(むしろ、Realm 0.102.1がリリースされると、現在はクラッシュします)。

食事を繰り返すだけで、食堂から下に行く必要がある場合は、次のようにします。

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
        }
    }
}

残念ながら、参照の各レベルでフィルターを繰り返す必要があるため、これには重複があります。

24
Thomas Goyne

これを試して:

let predicate = NSPredicate(format: "name == %@", "")
var canteens: [Canteen] = realm.objects(Canteen).filter(predicate).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
}
1
Dejan Skledar

レルムでは、フィルタリングのパラメーターとして関数を使用できます。だから、これは現在使用している私のソリューションです。

2つのフィルター関数:

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
}

この機能は、ユーザーがshowVegetarianOnly = true。また、食事が残っていないすべての行をフィルタリングします(ベジタリアンやビーガンはありません)。

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
    }
0
Daniel Storch