14

How do I auto increment a value stored in Firebase from an Android client?

Currently: I declare int id = 1. When I increment, I see the values 2, 3 etc. being stored. That's fine, but when I re-run the project, id is set equal to 1 again.

I want it to behave like a static variable, so I can create an id which will go from 1 to infinity without resetting.

UPDATED FAILED

I used the following to pass the Firebase reference and a string to the function incrementCounter.

if(language_chosen.equalsIgnoreCase("english"))
 {
   Firebase publRef = f.child("Language").child("English").child("Message");
   Firebase newPublRef = publRef.push();
   writeMsgActivity demo = new writeMsgActivity();
   demo.incrementCounter(newPublRef,the_msg_enter);                                 
  }

Now I try to use the passed reference and string at public void incrementCounter(Firebase publref,String my_msg) in the oncomplete method but it gives me an error.

   public void incrementCounter(Firebase publref,String my_msg) {
    publref.runTransaction(new Transaction.Handler() {
        @Override
        public Transaction.Result doTransaction(final MutableData currentData) {
            if (currentData.getValue() == null) {
                currentData.setValue(1);
            } else {
                currentData.setValue((Long) currentData.getValue() + 1);
            }

            return Transaction.success(currentData);
        }

        public void onComplete(FirebaseError firebaseError, boolean committed, DataSnapshot currentData) {
            if (firebaseError != null) {
                System.out.println("Firebase counter increment failed.");
            } else {
                System.out.println("Firebase counter increment succeeded.");

                Map<String, Object> publ = new HashMap<String, Object>();
                publ.put("pubMsg", my_msg);
                publ.put("id",currentData);
                publref.setValue(publ);
            }
        }
    });
}

UPDATED SOLVED

                final Firebase upvoteref = new Firebase("https://shareurday.firebaseio.com/Message/"+msg_id+"/upvotes"); 

            upvoteref.runTransaction(new Transaction.Handler() {
                @Override
                public Transaction.Result doTransaction(final MutableData currentData) {
                    if (currentData.getValue() == null) {
                        currentData.setValue(1);
                    } else {
                        currentData.setValue((Long) currentData.getValue() + 1);
                    }
                    return Transaction.success(currentData);
                }

                public void onComplete(FirebaseError firebaseError, boolean committed, DataSnapshot currentData) {
                    if (firebaseError != null) {
                        System.out.println("Firebase counter increment failed.");
                    } else {
                        System.out.println("Firebase counter increment succeeded.");
                    }
                }
            });

The variable msg_id is the random generated id from push.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
nothingness
  • 694
  • 3
  • 9
  • 25
  • I am not surely about what code you are using with Firebase and what Reload means here ?. But if you call same function (which set id=1) on reload you will get id 1. You have to set id in some file/database And keep updating in that storage. – aberry Mar 07 '15 at 14:11
  • 1
    I can set it in the database but everytime i re run the program it resets to the integer id=1 – nothingness Mar 07 '15 at 14:15
  • On every run you need to check existence in file/db... INSERT IF NOT EXISTS ELSE UPDATE . ur Q seems generic, but yes u need to track all concurrent changes if object/record is shared. – aberry Mar 07 '15 at 14:19

2 Answers2

17

Here's an example method that increments a single counter. The key idea is that you are either creating the entry (setting it equal to 1) or mutating the existing entry. Using a transaction here ensures that if multiple clients attempt to increment the counter at the same time, all requests will eventually succeed. From the Firebase documentation (emphasis mine):

Use our transactions feature when working with complex data that could be corrupted by concurrent updates

public void incrementCounter() {
    firebase.runTransaction(new Transaction.Handler() {
        @Override
        public Transaction.Result doTransaction(final MutableData currentData) {
            if (currentData.getValue() == null) {
                currentData.setValue(1);
            } else {
                currentData.setValue((Long) currentData.getValue() + 1);
            }

            return Transaction.success(currentData);
        }

        @Override
        public void onComplete(FirebaseError firebaseError, boolean committed, DataSnapshot currentData) {
            if (firebaseError != null) {
                Log.d("Firebase counter increment failed.");
            } else {
                Log.d("Firebase counter increment succeeded.");
            }
        }
    });
}
stkent
  • 19,772
  • 14
  • 85
  • 111
  • Can you show me how to pass in variables, im not good with this. – nothingness Mar 07 '15 at 17:03
  • What are you trying to achieve, exactly? If you save data using `push`, it is automatically generated with a unique id and would not require you to manually increment a counter. See e.g. https://www.firebase.com/docs/android/guide/saving-data.html#section-push . Let me know if that would be a better solution for you. – stkent Mar 07 '15 at 17:27
  • I need to create an id with each message so I can compare with another tree in replies. (I have this part done) for eg. each msg has an id and each reply to this msg will use that msg's id. So when i retrieve the replies it will be within the msg id. – nothingness Mar 07 '15 at 17:29
  • Then it seems like using `push`, and then calling `getKey` on the result, as described in the link I posted above, is probably the right solution for you? If so, I will update my answer to reflect this. – stkent Mar 07 '15 at 17:31
  • your answer is perfect, I just need to know how to use the passed reference and string. because i want the id of the msgs to be like 1,2,3 rather than jshfjkhhsbfjds from push. – nothingness Mar 07 '15 at 17:33
  • I have to go off now if you can update i would be greatly appreciated thanks for your time. – nothingness Mar 07 '15 at 17:33
  • Ok. In the last line of the code you added to the question, you have `publref.setValue(publ);`. Is that supposed to be `newPublRef.setValue(publ);`? – stkent Mar 07 '15 at 17:37
  • yes i passed the ref here : `incrementCounter(Firebase publref,String my_msg)` – nothingness Mar 07 '15 at 17:38
  • Maybe you want to replace the pair of lines `publ.put("pubMsg", my_msg); publ.put("id",currentData);` with the single line `publ.put(currentData, my_msg);`, but it's hard to tell because you're not indicating in what way your current solution is not working correctly... – stkent Mar 07 '15 at 17:56
  • It works with `publ.put("pubMsg", my_msg); publ.put("id",currentData);` except for my_msg. Because it was passed – nothingness Mar 07 '15 at 18:17
  • What is `the_msg_enter`? Is it an empty String? I don't see it being assigned anywhere. – stkent Mar 07 '15 at 18:51
  • Well it is an empty string here but in my code its from the text editor. – nothingness Mar 07 '15 at 18:53
  • So what is not working? "It doesn't work.." is not enough to go on. – stkent Mar 07 '15 at 19:04
  • Whats not working is the passing `incrementCounter(Firebase publref,String my_msg) `here – nothingness Mar 07 '15 at 19:23
  • What does "not working" MEAN here? I'm downvoting the question until you can edit to to provide some clear guidance. As the question stands it is not useful to anyone else. – stkent Mar 07 '15 at 19:30
  • Whats not working is the passing `incrementCounter(Firebase publref,String my_msg) ` after passing I want to use the passed variable but publ.put("pubMsg", my_msg); and publref.setValue(publ); they dont work in the inner methods of oncompleted. – nothingness Mar 07 '15 at 19:35
  • Try `public void incrementCounter(final Firebase publref, final String my_msg) {`. Your IDE warning probably indicated this was the appropriate fix. – stkent Mar 07 '15 at 20:08
  • It didn't save in the object rather it saved onto the reference for example. `final Firebase f = new Firebase("https://shareurday.firebaseio.com/msg"); ` it saves like this `msg:1` thats not what i want. I want it to save in the map object so like this `msg --> id:1` and it crashed my program after run. – nothingness Mar 08 '15 at 03:21
  • 1
    Did you try `publ.put(currentData, my_msg);` as I indicated earlier? – stkent Mar 08 '15 at 03:26
  • 1
    sorry for so much hassle, i got it working i will upload the solution. It was staring at me in the face. Thank you so much for your help!!! – nothingness Mar 10 '15 at 20:50
  • I'm working on the same issue in node and I was curious if getValue() in the example above is going out to he database. If so, I'm assuing runTransaction will block all calls until the transaction is committed. Does firebase not have a server side increment function like DynamoDB? Of course you could always argue not to mutate the state of an object and to just add to a different list. – Brett Mathe Nov 11 '16 at 04:48
5

A new feature is added to firestore to autoincrement values. As simple as

document("fitness_teams/Team_1").
  updateData(["step_counter" : FieldValue.increment(500)])

refer link: https://firebase.googleblog.com/2019/03/increment-server-side-cloud-firestore.html

Used below code in my project.

var firestore = Firestore.instance;
firestore.collection('student').document('attendance').updateData({'total_attendace': FieldValue.increment(1)});
AtulK
  • 51
  • 1
  • 2