Is this intended behavior of Firestore caching/offline flow? - android

My problem is with how Firestore offline mechanism works (or i don't understand it). Specific issue is that data is firstly synced from cache instead from online if network is available. It's quite easy to reproduce this:
In your firestore database, change data type of one of your variables to the wrong type. For example if we have document "Person" which contains variable "name" which is type String, change type to number and put 1 as value.
Your application will now crash, because Firestore SDK tries to parse data from that specific "Person" variable "name" int as String.
Now fix this issue on Firestore database and set "name" back as String and set value "test name".
Now open application (with network available).
The problem that i'm seeing in my own application is that the data is firstly taken directly from cache, and in cache, that "Person" variable "name" is still written as int (number on firestore) and the application crashes before it can take updated value from online, even though I have active network connection and I fixed data type directly on Firestore database.
The only solution to prevent crash in this situation is for user to clear app storage/cache and go into application again. Is this reproducable issue for other users as well? Is this intended behaviour?
If there is more explanation needed please write in comments.

This is the expected behavior. You should use some combination of strategies to prevent problems due to bad data:
Obviously, verify that all writes contain the types you expect. Use security rules to validate those types on the server.
Always assume that Firestore can give you unexpected data when you read a document. Before assuming that a type is what you think, actually check the type of that to make sure your assumption is correct.
Clearing cache should not be your production-worthy solution. Take steps to make sure that only good data goes in, and that only good data gets processed on the way out.

Related

How to know when Firebase DataSnapshot has been persisted server side

I'm building a chat using Firebase, using offline feature (keepSynced(true))
It works very well except that I cant find a way to know if the DataSnapshot message has indeed been saved server side, as if I query for the message Firebase will tell me that it exists (it does locally!).
I found about transactions but it does not save offline.
I also found about checking the connection status of Firebase, but it is a global status, and does not reflect one by one snapshot status.
The only solution that I found is adding a property "persisted" on my message objected, this property being set by a server side function, but that seems overkill for this purpose. I'm pretty sure Firebase does know locally which values are not persisted yet ?
On Android, when you perform any operation that writes, you will either get a Task object in return, or you may specify a CompletionListener as an argument. Either of these will indicate when the data is received by the server. If you don't use these, you have no other indication.
Using a Cloud Function to tag the location upon write is certainly another way to do it, if you can't hold on to the Task or CompletionListener.

Saving Revision in Cloudant Sync as an ordered LinkedHashMap, but not keeping the field's order in the server database (Cloudant), after replication

This is the inspection of the Revision object, with the LinkedHashMap correctly ordered
After saving it, if I retrieve the same document, I get this.
The 'body' field of the 'retrieved' object appears to be correctly ordered,
but if I get it as a Map, the map is disordered.
This is not a big deal to me but I have notice that after replication, the document is saved in the server with the same order that the disordered map I have retrieved on the app.
I really want to have the document correctly ordered on the server for readably purposes, is it possible?
I'm running my code on Android 6.0, even though, may this issue be related to the following link? LinkedHashMap entrySet's order not being preserved in a stream (Android)
Thanks for your help!
When you use the asMap method on a document object, Sync Android creates a shallow-copy Hashmap (see here). So that's why the Map retrieved from the local revision isn't ordered.
It looks like, deep in the depths, and don't quote me on it as it's a long time since I looked at this code, asMap is used to get the JSON to upload, meaning that unordered Map is used to create the JSON that's uploaded to Couch/Cloudant. (See here, but frankly this is deep in the guts after following quite a code path so probably not super-useful).
I think ordering on Java HashMaps depends on insertion order, which would explain why the order is the same on the server as for the asMap result from the local document object.

Parse objects overriding when using Local Datastore

I'm facing a weird issue using Parse's Local Datastore.
I have a Cloud function declared in backend that returns a list of ParseUsers, which can returns my current User.
The problem is when the function returns my User in the list, local currentUser gets overrided by the server data, resulting in a lost of information (i.e. authData).
Reading documentation from Parse I found this:
There are a couple of side effects of enabling the local datastore
that you should be aware of. When enabled, there will only be one
instance of any given ParseObject. For example, imagine you have an
instance of the "GameScore" class with an objectId of "xWMyZ4YEGZ",
and then you issue a ParseQuery for all instances of "GameScore" with
that objectId. The result will be the same instance of the object you
already have in memory.
I think this may be causing the problem.
Have you got any idea how to prevent this behaviour?
Thanks you in advance.
Well I finally found that this is due to a know Bug: https://developers.facebook.com/bugs/898928300168631/?search_id

Questions about the LocalDataStore in Parse

I am developing in iOS with Parse. My app required offline operation, so I had developed my own solution. However, Parse's introduction of the LocalDataStore obviates the need for my own solution. Since this is not released in iOS yet, I can only rely on documentation to prepare for this. I asked these questions on the Parse forum a week ago and the questions have been completely ignored by Parse. Can anyone answer these via experience with the Android version?
1) Objects pointed to by pointers and PFRelations will be pinned along with the pinned object. (That's correct, right?) Will PFFiles be pinned along with the object? Will the file data be locally available?
2) When a pinned object is modified, you have to SaveEventually it to push the changes to the Server, right? Does a Save on a pinned object save locally? Or does it do an "on-line" save?
3) When changes occur elsewhere to a pinned object, how do those changes get propagated to the pinned object in the LocalDataStore? Does the programmer have to explicit fetch the changes, or will it happen automatically?
4) Does the concept of logging in apply to the LDS? Do the ACLs operate in the LDS? Or does the local code have access to all objects in the LDS?
-Bob
I can give a basic answer from the Android side, but keep in mind the details may change as the Parse.com iOS version of LDS is released. My answers below come direct from the API docs are are bolded where I quote directly.
Let's go point by point:
1) Objects pointed to by pointers and PFRelations will be pinned along with the pinned object. (That's correct, right?) Will PFFiles be pinned along with the object? Will the file data be locally available?
Yes. From the Android docs: "Pinning a ParseObject is recursive, just like saving, so any objects that are pointed to by the one you are pinning will also be pinned."
2) When a pinned object is modified, you have to SaveEventually it to push the changes to the Server, right? Does a Save on a pinned object save locally? Or does it do an "on-line" save?
Again, from the Android docs this appears to be Yes. "Once you've saved some changes locally, there are a few different ways you can save those changes back to Parse over the network. The easiest way to do this is with saveEventually. When you call saveEventually on a ParseObject, it will be pinned until it can be saved. The SDK will make sure to save the object the next time the network is available."
3) When changes occur elsewhere to a pinned object, how do those changes get propagated to the pinned object in the LocalDataStore? Does the programmer have to explicit fetch the changes, or will it happen automatically?
The Android docs are pretty quiet about this process, but it's a safe bet you will have to query the server to synchronize the local datastore, the same way you do now when you have a local instance of an object after a query. That's all all the local data store is - a very persistent version of queried data.
4) Does the concept of logging in apply to the LDS? Do the ACLs operate in the LDS? Or does the local code have access to all objects in the LDS?
Logging in still applies, as does ACLs, as far as I can tell. The object permissions are still required for the local data. I haven't confirmed this with a test project in Eclipse, but the docs allude to this being the case.
A final note: The CEO of Parse, Ilya Sukhar, weighed in on the Google Group 3 days ago saying the iOS LDS is definitely on it's way. Here's hoping it's soon!

Syncronizing Android client with remote SQL-server database, using web service

I implemented an Android application that requires a set of data, taken by a SQL Server database. The application obtains the data calling a WS. After a first call to WS when the application start the first time, I need to maintain the data updated, according to the modify that may happens server-side (SQL server database).
For obtaining this result I perform, with a with a predefined frequency, a WS call, for knowing if data on database are changed. If new data are available, other web service is called for obtaining them.
This solution works fine for my ( I don't require real-time update). But, I think that this solution is too expensive in term of energy consumption, cpu consumption and network traffic.
Since, I immagine this is a very common problem I would know if exists a generic way to deal with it.
I suggest you to use extra fields. Add four colums to your local tables in Android :
TRANSACTING_FLAG : Set it to true when you are posting or updating this resource on the server
REQUEST_STATE : Set this flag to POSTING / UPDATING / DELETING etc.
RESULT_CODE : Set this field to the last result code received by the server for this particular resource.
TIMESTAMP : Period after wich data has to be updated
Workflow is simple :
When you retrieve data for your server just check if the last updated timestamp of your resource is superior to the cache timestamp you have defined before. If the timestamp is superior perform a request to update data. The transacting boolean let you know that a particular resource is actually synchronizing with the server. The result code lets you know if the request has failed or not and enventually retry it when the network is available. Doing this way you will maintain the persitence between your local and remote database because at any moment you can check the "synchronized state" of any local resource thanks to extra fields seen before.
I made a library to handle this. Take a look to RESTDroid. Even if the cache functionnality is not handles, you will be able to simply add it.
What you do is ok for most cases. You can take advantage of Google Cloud Messaging, but it needs time and effort to get implemented. I would stay with your solution.
You could look into Query Notifications, using something like SqlDependency - http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldependency.aspx. You can use this to track whether the results of a query change and to inform an application when this happens.
There are restrictions on the query you can use, and cost on the server is similar to an indexed view. You need .NET for this, by the way. If implemented in your Web Service, you would have to implement some kind of subscribe feature for your android, so that notifications could be pushed to it.
Another option to reduce the cost of checking for changes could be SQL Server Change Tracking - http://msdn.microsoft.com/en-us/library/bb933875.aspx

Categories

Resources