Fetching every row of a table with Parse and PFQuery

Recently i came across a problem when using the Parse iOS SDK. Unknown to me, the Parse PFQuery object will only return 100 results by default. Which unfortunately, i found out the hard way when one of my apps stopped returning results when the table hit the 100 rows mark. As the Parse documentation says hidden away somewhere:

You can limit the number of results by setting limit. By default, results are limited to 100, but anything from 1 to 1000 is a valid limit:

So what if we want more than 100 results? This question on the Parse support site has a great answer from Héctor Ramos on how to return all the rows in a table with a PFQuery. Although.. as great as the answer is, it only really points you in the right direction. And does not supply a final solution to fetch every result using PFQuery. 

I came up with a little sollution using a recursive block, which will use a PFQuery object to query Parse until every result has been returned.

+ (void)findAllObjectsWithQuery:(PFQuery *)query withBlock:(void (^)(NSArray *objects, NSError *error))block
{
    __block NSMutableArray *allObjects = [NSMutableArray array];
    __block NSUInteger limit = 1000;
    __block NSUInteger skip = 0;
    
    typedef void  (^FetchNextPage)(void);
    FetchNextPage __weak __block weakPointer;
    
    FetchNextPage strongBlock = ^(void)
    {
        [query setLimit: limit];
        [query setSkip: skip];
        
        [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
            if (!error)
            {    
                // The find succeeded. Add the returned objects to allObjects
                [allObjects addObjectsFromArray:objects];
                
                if (objects.count == limit) {
                    // There might be more objects in the table. Update the skip value and execute the query again.
                    skip += limit;
                    [query setSkip: skip];
                    // Go get more results
                    weakPointer();
                }
                else
                {
                    // We are done so return the objects
                    block(allObjects, nil);
                }
                
            }
            else
            {
                block(nil,error);
            }
        }];
    };
    
    weakPointer = strongBlock;
    strongBlock();
        
}

So to use this method we can simply do the following:

PFQuery *query = [PFQuery queryWithClassName:@"myClassName"];

[ParseProxy findAllObjectsWithQuery:query withBlock:^(NSArray *objects, NSError *error) {
	if(!error)
	{
		NSLog(@"Loaded All Objects: %@",objects);
	}
}];

Easy!

Tags: Parse PFQuery iOS apple objective-c blocks