Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sync between Parse and localDataStore

I am having trouble synchronizing my local data with Parse data when using ´enableLocalDataStore´. If I don't use local storage everything is fine, but I would like to minimize calls to Parse server. I understand that if I use ´saveEventually´ for newly created objects these will persist (pinned) locally and be synced with Parse when internet connection is available. This also works fine. My problem is that I don´t know the best method to update the local 'dataStore' with Parse 'dataStore' except to call a method that fetches changes remotely and updates locally. Currently, use the following:

-(void) fetchAllFavorites{
  PFQuery *query = [PFQuery queryWithClassName:@"UserStats"];
  [query fromLocalDatastore];

  [[query findObjectsInBackground] continueWithBlock:^id(BFTask *task) {
      if (task.error) {
      }
      else
      {
           [PFObject pinAll:task.result];  
      }
      return task.result;
  }];
} 

This approach does not account for changes that may have occurred in Parse 'dataStore'. I could just unpin all local objects and fetch whatever is in Parse by calling a method directly. However, I would think there would be a better approach that seamlessly syncs local changes with changes in the Parse 'dataStore'? Is that not the idea behind allowing the use of 'localDataStore' in the first place ? Currently, I can only see that this works one way: you store data locally and then update the Parse 'dataStore' manually, but you don't really sync between these. At least this is the idea I get from some of the examples and I wonder if anyone has a good approach to how to: how to enable 'localDataStore' that is continuously synchronized with Parse 'dataStore'? Any suggestions and examples would be very helpful. I am programming in Cocoa but Java examples would also be great. Thanks, T.

like image 829
Trond Kristiansen Avatar asked Jan 22 '15 00:01

Trond Kristiansen


2 Answers

My solution to this was to do a local query, and if nothing is there then query the server. In my settings page I have a function that will "sync" with server, fully refresh the pinned objects basically. This isn't that necessary since any time the user edits, removes, or adds an object, I am calling saveEventually, deleteEventually, pinInBackground, unpinInBackground, as appropriate. My startup function looks like this. If local objects aren't found, the server is queried and they are pinned so that next time it will only be local.

PFQuery *localQuery = [PFQuery queryWithClassName:@"ClassName"];
[localQuery fromLocalDatastore]; // and any other constraints
[localQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
    if(objects.count > 0) {
        self.objects = objects;
    } else {
        PFQuery *remoteQuery = [PFQuery queryWithClassName:@"ClassName"];
        [remoteQuery findObjectsInBackground:^(NSArray *objects, NSError *error) {
            if (objects) {
                self.objects = objects;
                [PFObject pinAllInBackground:objects];
            }
        }];
    }
}];
like image 156
Raesu Avatar answered Oct 23 '22 12:10

Raesu


My approach was to write an utility that checks whether something was updated or deleted in the cloud. Everytime I needed to do an update I called:

[[ParseLocalDataStoreManager sharedInstance]updateClasses:classes];
//classes is a NSArray

I kept track of which classes were already in the localStore and which were not. If a class was not, then I queried and pinned all of its objects. If it was, I only updated the objects that were modified in the cloud, after the last date I updated. I used Parse's

[query whereKey:@"updatedAt" greaterThanOrEqualTo:lastUpdated];

and kept record of lastUpdated in 'NSUserDefaults'.

To delete the objects that were no longer in the cloud, I wrote a small cloud function that returned the objects on the cloud for a certain class. Then I compared them to what I had in localStore, and deleted those that were not in the Cloud.

In my case I updated everytime the user opened the app, since no real-time updates were needed. But if you need real time updates, you can set a timer, and call the function update with the classes you want to update in real time.

I uploaded the utility to github: https://github.com/timpalade/ParseLocalDataStoreManager

Intstructions as well as the cloud code can be found on github. Hope this helps!

like image 37
Tim P Avatar answered Oct 23 '22 11:10

Tim P