Sync between Parse and localDataStore
Asked Answered
A

2

9

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.

Allinclusive answered 22/1, 2015 at 0:5 Comment(4)
FYI querying the local data store uses an API request just the same as remotely querying.Sterol
I know but it still only queries locally. I wish it would query locally first and if no results found, search remotelyAllinclusive
Have you not looked into their caching policies this could circumvent even needing local datastoreSterol
Yes, but you are not allowed to change the policy once you enable ´localDataStore´. At least this was my experience when I tried different settings with e.g. kPFCachePolicyCacheElseNetwork.Allinclusive
O
2

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];
            }
        }];
    }
}];
Osi answered 10/9, 2015 at 20:2 Comment(2)
How does this work for pulling new updates after you already have some initial local data? The example above only really makes sense on a fresh app install, if the user had remote data but nothing stored locally yet. How do you detect new updates that have happened server-side while the client was disconnected? (for example: new chat messages received since the last time the app was launched). The code above would only pull your previous chat messages you had saved locally.Enarthrosis
I have messaging in my app and I update that separately from this "ClassName" object. My example shows how I'm managing an object that is only updated by the owner. In messaging, I would pin those messages as they come in (I use push notifications to either refresh the screen or show a notification). Another option is to just always run a remote query on startup and if it returns, then unpin and pin all objects.If it doesn't (no connection), just use the currently pinned objects.Osi
M
2

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!

Marianomaribel answered 5/3, 2016 at 12:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.