Search code examples
filterrealmpredicate

Realm Filter Issue


I have Inventory Model & Stock Model as realm object, whereby Inventory is to save as the product Category Name (eg. COKE / PEPSI ), and Stock as the product name (eg. Coke Regular, Coke Light, Coke Vanilla)

In my Parent Table, TableView are showing

  • COKE - 150 left
  • PEPSI - quantity left

when selectedRowAt COKE, tableView will instantiate segue to another TableView called StockTable, which will show

  • Coke Regular : 100 unit left
  • Coke Light : 30 unit left
  • Coke Vanilla : 20 unit left

Currently I have a button with 2 option when tapped at ParentTable :

  1. to show all inventory with more than 1 quantity = ISSUE
  2. to show all inventory without quantity count = PERFORMING

I am having issue to filter and query option 1, hence "totalUnit" is created with auto-update when perform realm.write to update totalUnit every single time, which is very risky for wrong information/data entry.

For me I want to query the data based on StockModel's quantity sum(property:"quantity") instead of updating the totalUnit in realm.write as it will be very risky for future and to prevent bug.

So I had created two function

  1. showStockList_byTotalUnit() -> Results<StockModel> Currently Using
  2. showStockList_byStockQuantity() -> [StockModel]

which both are working accordingly to what I wanted to see as result, However, I am not sure using [StockModel] is the same as Results<StockModel> or not as all my other tableView are based on Results<Object>? instead of Array.

Question

  1. I want to remove totalUnit from InventoryModel and achieve ParentTable to show the total unit from its own StockModel's quantity
  2. Can I convert [StockModel] to Results<StockModel>?
  3. Is showStockList_byStockQuantity any issue that I might encounter?
class InventoryModel:Object {
    @objc dynamic var name:String = ""
    @objc dynamic var info:String = ""
    @objc dynamic var category:String = ""
    @objc dynamic var totalUnit:Int = 0 **THIS IS UPDATED BASED ON USER DELETE/ADD DATA, WISH TO REMOVE THIS**

   
    ///Childs
    var ofStock = List<StockModel>()
class StockModel:Object {
    @objc dynamic var name:String = ""
    @objc dynamic var quantity:Int = 0
    @objc dynamic var purchasePrice:Double = 0
    @objc dynamic var totalCost:Double = 0
    @objc dynamic var purchaseDate:Date?
    
    ///Parent
    var parentInventory = LinkingObjects(fromType: InventoryModel.self, property: "ofStock")
    
**InventoryModel**

func showStockList_byTotalUnit() -> Results<StockModel>? {
        let showActiveStock = self.ofStock.sorted(byKeyPath: "name", ascending: true).distinct(by: ["name"]).filter("totalUnit > %@",0)
        return showActiveStock
        
    }

**Inventory Model**

    func showStockList_byStockQuantity() -> [StockModel] {
        let allStocks = self.ofStock.sorted(byKeyPath: "name", ascending: true).distinct(by: ["name"])
        var activeStocks:[StockModel] = []
        
        for stock in allStocks.enumerated() {
            let stockQuantity:Int = realm!.objects(StockModel.self).filter("name == %@", stock.element.name).sum(ofProperty: "quantity")
            
            if stockQuantity > 0 {
                activeStocks.append(stock.element)
            }
        }
        return activeStocks
    }


Solution

  • Let me shorten and repeat the question

    The objective is to get the qty of a particular InventoryModel based on the StockModel quantities stored in the ofStock list. (instead of storing it in InventoryModel totalUnit property).

    Using the InventoryModel and StockModel in the question, if we create an inventory model for widget

    let inv = InventoryModel()
    inv.name = "Widget"
    

    and then add two StockModel objects to its ofStock List

    let sm0 = StockModel()
    sm0.quantity = 1
    
    let sm1 = StockModel()
    sm1.quantity = 2
    
    inv.ofStock.append(objectsIn: [s0, s1])
    

    If we then want to get the total inventory available for the Widget object, it's a single line

    let sum: Int = realm.objects(StockModel.self).filter("ANY parentInventory.name == 'Widget'").sum(ofProperty: "quantity")
    print(sum)
    

    and the output is 3

    Note that we are transversing back through the StockModels to get the parent they belong to.

    EDIT

    The OP also wanted to have a query to do the following (from the comments)

    I want to query for all InventoryModels that have ANY stock models that have a quantity > 0

    Here's the query that returns all InventoryModel objects where any StockModels in the ofStock property have a quantity property greater than 0

    let results = realm.objects(InventoryModel.self).filter("ANY ofStock.quantity > 0")