imperiumlabs / GeoFirestore-Android

GeoFirestore for Android - Realtime location queries with Firestore
MIT License
123 stars 37 forks source link

Write only 1 time to Firestore #42

Open betegon opened 4 years ago

betegon commented 4 years ago

I followed the README , that writes the geopoint and geohash to an existing firestore document.

val collectionRef = FirebaseFirestore.getInstance().collection("ExistingCollectionUID")
val geoFirestore = GeoFirestore(collectionRef)
geoFirestore.setLocation("ExistingDocumentUID",GeoPoint(37.587,-122.405)){ exception ->
    if (exception != null){
        Log.d(TAG,"Location saved on server successfully!")
    }
}

The flow I am follow currently is:

  1. Write user info to a new document in Firestore

  2. Add GeoFirestore information to that document

This result in two writes into Firestore, doubling the price of the bill.

is there a way I can attach GeoFirestore information to the other document info and make only one write into Firestore?

Meaning that, I can store information to a variable and write it to firestore with the other data I have.

Thank you for your time and effort in GeoFirestore-Android.

Supercaly commented 4 years ago

Short answer: No Long answer: The library didn't consider if the document was created two seconds ago or two years ago; hypothetically you can add geo-data to an old document. I think that the typical use-case will be adding a new document along with with geo-data, so a method that let's add all in one go is well suited. I mark this issue as an enhancement hoping that someone will implement this functionality.

betegon commented 4 years ago

Perfect, I did a similar thing yesterday to try it out.

I created myself the g and l and then upload all the object to Firestore without using GeoFirestore. This will result in only one write, but it will also make people don't use GeoFirestore for that.

How do you see that functionality? a) As a function that returns g and l so user can handle them as they want. b) As a function that is given a hashmap and it adds to it g and l and upload all to Firestore (this will be 2 functions I guess)

I lean towards a).

Let me know what do you think about it, please.

Supercaly commented 4 years ago

I think there should be a function which takes your document POJO (or your map of fields) and your geo data, computes and adds g and l to it and upload all the document in one go

This could be a pseudocode

geoFirestore.addDocument(document, geoLocation) {
   l = get l (geoLocation)
   g = get g
   add g and l to document
   upload document to firestore
}
betegon commented 4 years ago

Hi @Supercaly , I have been thinking about your approach to this situation:

  1. If you accept a document (POJO or hashmap), it will be difficult to handle errors, due to the fact that Firestore only accept certain datatypes, meaning that it will cause an error if there is a datatype Firestore does not accept.

Here is an example

// Valid hashMap for Firestore
val docData = hashMapOf(
    "stringExample" to "Hello world!",
    "booleanExample" to true,
    "numberExample" to 3.14159265,
    "listExample" to arrayListOf(1, 2, 3),
    "nullExample" to null
)

// Invalid hashMap for Firestore
val docData = hashMapOf(
    "stringExample" to "Hello world!",
    "dateExample" to LocalTime(10,0)
)

Maybe I am taking a wrong approach, as I have less than a year of experience with Java/kotlin.

It is a good feature to develop because it will let you handle all Firestore related operations including Locations using GeoFirestore, which is pretty awesome.

Could you give a bit more explanation on this please?

Supercaly commented 4 years ago

Yeah, I forgot error handling If I recall correctly the Firestore way of adding a document has a callback on failure, so our hypothetical method will take as argument a function (the on error callback), internally listen the firebase one and notify the user (who is listening to our callback) in case of some error.

in Kotlin the method declaration will be something like:

fun addDocument(document: Object, location: GeoLocation, onError: (e: GeoFirestoreError)->Unit)
cbarrios commented 4 years ago

Hi @betegon. I have the same problem but I have tried with firestore persistence enabled and it will result in just one read and one write with listener. However, when you switch the persistence to false, then you will be billed for 2 reads (the second due to the onDocumentChanged because of the second update to the initial doc) and 2 writes.

firestore.collection("my-collection").add(data).addOnCompleteListener(task -> {
                if(task.isSuccessful()){
                    String docId = task.getResult().getId();
                    geoFirestore.setLocation(docId, coordinates, e -> {
                        if(e == null){
                            Toast("Doc added successfully.");
                        }else{
                            Toast(e.getMessage());
                        }
                    });
                }else{
                    Toast(task.getException().getMessage());
                }
            });
betegon commented 4 years ago

Hi @cbarrios

If you have the same problem as me, what do you think of @Supercaly idea of a method like addDocument proposed in his latest comment?

As I am kind of a noob in kotlin, I don't know how to implement it, maybe if I look to you for guidance I could achieve it!

I will have a look at your code and I will come back to you.

cbarrios commented 4 years ago

Hi @cbarrios

If you have the same problem as me, what do you think of @Supercaly idea of a method like addDocument proposed in his latest comment?

As I am kind of a noob in kotlin, I don't know how to implement it, maybe if I look to you for guidance I could achieve it!

I will have a look at your code and I will come back to you.

Hi @betegon I do think that having such a method is the correct way to go since the code I put works only if firestore cache persistence is enabled (which by default is). When set to false, then the code will still cost 2 writes.

JobGetabu commented 4 years ago

You could try this way: https://github.com/JobGetabu/DroidGeoFire