Java – Firebase returns the keys of child nodes in different order on different devices/Android versions

Firebase returns the keys of child nodes in different order on different devices/Android versions… here is a solution to the problem.

Firebase returns the keys of child nodes in different order on different devices/Android versions

I’m taking a snapshot of data from my Firebase database to retrieve a list of users, but the order of keys returned varies depending on the Android version/device used.

I’ve shortened the method for demonstration purposes, but it basically looks like this:

public void getUsers(){
    Firebase ref = new Firebase("https://myFirebaseID.firebaseio.com");
    final Firebase userRef = ref.child("users");

userRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot snapshot) {
           snapshot.toString();
        }                                                           
    });
}

I changed the order of the data I got by calling toString() on the snapshot object (snapshot.toString()).

I’ve tried it on 4 devices. 2 running Lollipop (Nexus 7 5.1.1 and Galaxy s4 5.01) return data in the same order. The other two devices (HTC Sensation 4.0.3 and Motorola G2 4.4.4) return data in the same order (but in a different order than Lollipop devices).

There is no difference in the code used, and the data in the database has not changed at all when I retrieve the snapshot.

This is the order of data on 4.4.4 and 4.0.3 devices:

DataSnapshot { 
  key = users, 
  value = {
    114585619420240714499={
      **userIDOfCUser**=114585619420240714499,
      **NameOfCUser**=testName,
      **EmailOfCUser**[email protected],
      **friends**={
        103902248954972338254={
          **userIDOfFriend**=103902248954972338254, 
          **NameOfFriend**=testName2 
        }
      }
    }  

This is the order of data on 5.1.1 and 5.01 devices:

DataSnapshot { 
  key = users, 
  value = {
    114585619420240714499={
      **NameOfCUser**=testName, 
      **userIDOfCUser**=114585619420240714499, 
      **friends**={
        103902248954972338254={
          **NameOfFriend**=testName2 ,
          **userIDOfFriend**=103902248954972338254
        }
      }, 
      **EmailOfCUser**= [email protected]
    }
  }
}

Why is data being transferred in a different order depending on the Android version/device used? Are there any other differences that I don’t know about?

Edit:
When traversing the snapshot as follows, the different order of the keys persists in different versions of Android:

public void getUsers2(){

Firebase ref = new Firebase("https://myFirebaseID.firebaseio.com");
  final Firebase userRef = ref.child("users");
  userRef.addListenerForSingleValueEvent(new ValueEventListener() {

@Override
    public void onDataChange(DataSnapshot snapshot) {
        for (DataSnapshot keys : snapshot.getChildren()) {
            String to temporarily store the whole child of the inidividual user's DB node ----> It still produces different order of the keys 
            String tempKey = keys.getValue().toString();

The problem persists if I code it like this as well. 
            String tempKey2 = snapshot.child(keys.getKey()).getValue().toString();

}
    }
  });
}

Solution

Firebase’s REST API contains Documentation for this warning:

When using the REST API, the filtered results are returned in an undefined order since JSON interpreters don’t enforce any ordering. If the order of your data is important you should sort the results in your application after they are returned from Firebase.

In other words: the properties in a JSON object can be in any order. The JSON parser is free to rearrange them as needed.

Instead of using the REST API, you are using the Firebase Android SDK. If such reordering is hidden from you or (when it is not possible) explicitly tell you what the order is (e.g. previousChildName argument to the onChildAdded callback)

But from the data you

display, it looks like you’re parsing the output of dataSnapshot.toString(). While this is entirely true, it does mean that you choose to process the order yourself. In general, it’s best to stick with the Firebase Android SDK’s approach, as they handle things like ordering for you:

public void onDataChange(DataSnapshot snapshot) {
  for (DataSnapshot friendSnapshot: snapshot.getChildren()) {
    System.out.println(friendSnapshot.child("NameOfFriend").getValue());
  }
} 

Update

Judging by your update, it seems that you have a problem with the user and then also want to iterate through their friend. Using the Firebase Android API, you can use:

Firebase ref = new Firebase("https://myFirebaseID.firebaseio.com");
final Firebase userRef = ref.child("users");
userRef.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot userSnapshot) {
    DataSnapshot friendsSnapshot = userSnapshot.child("friends");
    for (DataSnapshot friendSnapshot : friendsSnapshot.getChildren()) {
      System.out.println(friendSnapshot.child("NameOfFriend").getValue());
    }
  }
});

Related Problems and Solutions