Lazy Loading on CBLQuery Fetching


#1

Hi,
I have documents like bellow

Customer {
name: String!
purchaseOrderUpdatedDate: NSDate!**
}

PurchaseOrders{
customerID: String! // This is Customer document id
}

I want to get all the customers with their PurchaseOrders.

For this, i request 20 customers first with skip feature on CBLQuery and again requesting each customer with their purchase orders.

while doing this process first time i’m getting data lazily . once i go back to some where and again requesting the data, i’m getting very quick result. i’m wonder why this only happens on this models objects. rest of CBLQuery fetching working perfectly. Please assist me on this situation.


#2

You haven’t said what’s going wrong, or shown what the view or query look like.


#3

@Jens, The problem is taking time to fetch records on first time. once date came, when again i request same request data getting quickly. please see my models above.

Here is my code snippet.

 let sortDesc : NSSortDescriptor = NSSortDescriptor(key: "PurchaseOrderUpdatedDate", ascending: true)
            
            let result = self.eventsObj.getMatchedDocsWithPredicate(predicate, withOrderList: [sortDesc], andWithStartIndex: self.skipIndex, andWithLimit: Constants.kLimitRecords)  //Here i will get customers, who have purchase orders. 
            
            var tempArray : [AnyObject] =  [AnyObject]()
            
            _ = result.map {
                var dict : [String : AnyObject] =  [String : AnyObject]()
                
                let row : CBLQueryRow = $0 as! CBLQueryRow
                let obj:CustomerModel = CustomerModel(forDocument: row.document!)
                dict[self.kName] = obj.name
                
                let predicate2  = NSPredicate(format: "documentType == %@ && customerID == %@", argumentArray: [NSStringFromClass(PurchaseOrderModel), (row.document?.documentID)!])
                
                
                let result = self.eventsObj.getMatchedDocsWithPredicate(predicate2,withOrderList: ["-updatedDate"]) // Here we will get each customer with their purchase orders. 
                
                dict[self.kPurchaseOrdersList] = result
                
                tempArray.append(dict)
                
                
            }
            self.resultList.removeAll()
            self.resultList = tempArray

//Methods Definition

func getMatchedDocsWithPredicate(predicate: NSPredicate, withOrderList orderlist: [AnyObject]!, andWithStartIndex startindex: AnyObject!, andWithLimit limit: UInt) -> [AnyObject]! {

    let query = try! CBLQueryBuilder(database: Constants.appDeleRef.database, select: nil, wherePredicate: predicate, orderBy: orderlist)
   
    let queryObj : CBLQuery  = query.createQueryWithContext(nil)
    queryObj.descending = true
    queryObj.skip = startindex as! UInt
    queryObj.limit = limit
    let result : CBLQueryEnumerator = try! queryObj.run()
    var listData = [AnyObject]()
    listData = result.allObjects
    return listData
}

#4

You’re creating a new QueryBuilder for every query. Don’t do that. Building the view index is slow.

Instead create a QueryBuilder whose predicate has parameters and keep that object around. Then you can query it with different parameter values.


#5

Do you mean about this statement

let query = try! CBLQueryBuilder(database: Constants.appDeleRef.database, select: nil, wherePredicate: predicate, orderBy: orderlist)

ok i can create once and will reuse on every time. What do you mean about Building the view index is slow do you mean about

let queryObj : CBLQuery = query.createQueryWithContext(nil)

I read CBLQueryBuilder but how can i do pagination on CBLQueryBuilder.


#6

A QueryBuilder creates a view when it’s instantiated. The view is persistent, but the first time it’s queried it will need to generate its index. That can take time since it involves a linear scan of all documents, and running the map function on every document.


#7

So any alternative to get quick result on first time also. i will change my QueryBuilder to make it re-usable not like to create every time. but i facing this is issue only on customer and purchase models. rest of all are getting very fast. so is there any alternative to get quick result on first time too?


#8

You can run a trivial query ahead of time, to get the indexing out of the way. For example, set the limit=1. You can run this query asynchronously so it doesn’t block your UI.


#9

@jens, thanks for reply, if you provide example it would be great.