0

I want to append a String to my List on the Firebase Realtime Database. (My code already works but there is a problem)

So the Database looks like this:

message:
    0: "some string"
    1: "another string"
    2: "some string"

But I think the problem with this code would be, that if somebody reads the numbers of messages and then wants to write a message there would be a problem, when another user writes a message in the mean time (because the number of messages would change).

FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference myRef = database.getReference("message");

myRef.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        myRef.child(
            String.valueOf(dataSnapshot.getChildrenCount())
            ).setValue("SOME STRING");
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {

    }
});
113408
  • 3,364
  • 6
  • 27
  • 54

1 Answers1

0

Trying to use sequential numeric indexes (also often referred to as array indexes or auto-increment values) in a multi-user Firebase is an anti-pattern for a few reasons.

  • As you've already noted yourself, there's a chance of users overwriting each other's data. This is fixable however by using a transaction, which is the way to go if you need to property a value based on its existing value. The reference documentation for the JavaScript DatabaseReference.transaction method have this example that is pretty much what you need:

    // Increment Ada's rank by 1.
    var adaRankRef = firebase.database().ref('users/ada/rank');
    adaRankRef.transaction(function(currentRank) {
      // If users/ada/rank has never been set, currentRank will be `null`.
      return currentRank + 1;
    });
    

    The syntax in Android is slightly more involved, but would work the same.

  • While a transaction works, this means that the application will only work when the user is connected to the server. When they're offline, the transaction will fail.

For these reasons Firebase apps typically use a different mechanism to generate their keys. The built-in push() method of the API generates a unique, always-incrementing key. While this key is not as readable as your sequential, numeric keys, they do address both of the above problems without the need for you to write more code for it yourself. With push() adding a message becomes as simple as:

final DatabaseReference myRef = database.getReference("message");
myRef.push().setValue("SOME STRING");

Note that this topic has been covered quite a bit already, so I recommend also checking out:

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • But when I use "push", how can I then get the sequence of the String when I want to read them? – ShadeCoding Jan 26 '19 at 15:34
  • I'm not sure I understand what you mean there. You always get the key of an child node the same way, no matter how it was generated with `DataSnapshot.getKey()`. But the important difference is that you don't need to know the existing keys to generate a new/next key if you use `push()`. – Frank van Puffelen Jan 26 '19 at 16:05
  • If you want to get all the keys in your `onDataChange` then something like: `for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) { System.out.println(childSnapshot.getKey()); }` – Frank van Puffelen Jan 26 '19 at 16:05