Support Topics Documentation Slack YouTube Blog

Swift 3-4 Retrieving large set with page size and offset.


(Jorgen Andreasson) #1

Has anyone an example how this is done?

I get the setPageSize and setOffset part. Not quite clear on when/how to call queryBuilder?.prepareNextPage() part.
If anyone has something so I can see how to loop things, I would be most appreciative.
As an example, say I have 250 objects in a custom class that I need to get into an array in iOS/macOS.


(Sergey Chupov) #2

Hi Jorgen,

Here you go, this section in the docs explains this with examples: https://backendless.com/docs/ios/doc.html#data_data_paging


(Jorgen Andreasson) #3

Thank you, but it doesn’t really explain it.

There is two calls, by the look of things, but not really how to string them together.
I was hoping someone had done it and could show the link between them.


(Sergey Chupov) #4

What .prepareNextPage() call does is merely setting offset = offset + pageSize. It doesn’t perform any network calls. Thus, you call it before calling .find() to retrieve the next page of data.

For example, of you have 250 data objects, here’s the sequence of actions you need to retrieve them all:

queryBuilder.setPageSize(100); // set to max initially
Backendless.Data.find( queryBuilder ); // retrieves first 100 objects (0-99)
queryBuilder.prepareNextPage();
Backendless.Data.find( queryBuilder ); // retrieves second 100 objects (100-199)
queryBuilder.prepareNextPage();
Backendless.Data.find( queryBuilder ); // retrieves remaining objects, since there are less than 100 left (200-250)

(note that this is just a pseudocode, not an actual code to run)


(Jorgen Andreasson) #5

OK, I will give that a go.


(Jorgen Andreasson) #6

Is there any call/signal to say that I have reached the end?

E.g. if I have your line 3 & 4 running in a loop, I need something to finish the loop.


(Sergey Chupov) #7

You can check whether the resulting collection is empty, it will indicate that there’s no data left.

Continuing my example:

...
queryBuilder.prepareNextPage();
Backendless.Data.find( queryBuilder ); // retrieves remaining objects, since there are less than 100 left (200-250)
queryBuilder.prepareNextPage();
Backendless.Data.find( queryBuilder ); // returns empty collection

(Sergey Kukurudzyak) #8

or you can count by query https://backendless.com/docs/ios/doc.html#data_get_object_count


// get number of objects for a query
dataStore.getObjectCount(queryBuilder: DataQueryBuilder!,
                         response:((NSNumber?) -> Void)!, 
                         error:((Fault?) -> Void)!)

then if page size is 10 and there is 253 records, you will have 26 pages


(Jorgen Andreasson) #9

Solved it.

The loop of the secondary finds needed to be blocking and within the first fin block.
You can close this now.
Thank you.


(Robert J) #10

Whats the best way to do this without blocking the UI?
https://backendless.com/feature-17-data-paging-or-how-to-efficiently-load-large-data-sets-in-a-mobile-app/
This seems to be missing some code, at least for the swift side.


(Sergey Kukurudzyak) #11

there is sample with paging

func advancedPagingAsync() {

        var startTime = NSDate()

        var offset = 0
        var query = BackendlessDataQuery()
        query.queryOptions.pageSize = PAGESIZE // set page size
        backendless.persistenceService.of(Restaurant.ofClass()).find(
            query,
            response: { (var restaurants : BackendlessCollection!) -> () in
                println("Total restaurants in the Backendless starage - \(restaurants.totalObjects)")
                self.getPageAsync(restaurants, offset:offset, startTime:startTime)
            },
            error: { (var fault : Fault!) -> () in
                println("Server reported an error: \(fault)")
            }
        )
    }

}


(Robert J) #12

This part is missing. Where is it calling?


(Sergey Kukurudzyak) #13

ok, now I understand your question, we will add this part to the doc and notice you


(Robert J) #14

Thanks for the quick reply and fix!


(Olga Danylova) #15

Hello!

Are you using Backendless v3 or Backendless v5? These methods are different in different versions of Backendless.

Regards, Olga


(Robert J) #16

Backendless v5

Robert


(Olga Danylova) #17

I’ll provide a simpler example:

// Setup pageSize and offset

let pageSize: Int32 = 5
var offset: Int32 = 0

// Create queryBuilder with this params

var queryBuilder = DataQueryBuilder()!
queryBuilder.setOffset(offset)
queryBuilder.setPageSize(pageSize)

// Call this method to load objects with paging

func loadObjects() {
    let dataStore = Backendless.sharedInstance()?.data.ofTable("Restaurant")

	// Total amount of objects in the table
    let totalObjects: Int32 = dataStore?.getObjectCount()?.int32Value ?? 0	
        
    dataStore?.find(queryBuilder, response: { loadedObjects in
        let loadedObjectsCount: Int32 = Int32(loadedObjects?.count ?? 0)
        print("Loaded \(loadedObjectsCount) objects in this page")
            
        self.offset += loadedObjectsCount

		// Check if we have more objects to load
        if self.offset < totalObjects {
			
			// update queryBuilder offset
            self.queryBuilder.prepareNextPage()

			// loading objects with new offset
            self.loadObjects()
        }
    }, error: { fault in
        print("ERROR: \(fault!)")
    })        
}

As I have 12 objects in my Restaurant table the result is:

Loaded 5 objects in this page
Loaded 5 objects in this page
Loaded 2 objects in this page

Hope it helps you

Regards,
Olga