Ordered Data

How Your Data is Ordered

By default, children at a Firebase location are sorted lexicographically by name. Using Push / childByAutoId can generate child names that naturally sort chronologically, but many applications require their data to be sorted in other ways. Firebase allows developers to specify the ordering of items in a list by specifying a custom "priority" for each item.

The order of children is determined by their priority and name as follows:

  1. Children with no priority come first.
  2. Children with a number as their priority come next. They are sorted numerically by priority (small to large).
  3. Children with a string as their priority come last. They are sorted lexicographically by priority.
  4. Whenever two children have the same priority (including no priority), they are sorted by name. Numeric names come first (sorted numerically), followed by the remaining names (sorted lexicographically).

Here is an example of how your data will be sorted:

var usersRef = new Firebase('https://SampleChat.firebaseIO-demo.com/users/');

usersRef.child("Andrew").set({name: {first: 'Andrew', last: 'Gee'}});
// User "Andrew" will be first because it has no priority.

usersRef.child("Matt").set({name: {first: 'Matt', last: 'Jones'}});
// User "Matt" will be second because it has the same priority as "Andrew"
// and "Andrew" comes lexicographically before "Matt"

usersRef.child("James").setWithPriority({name: {first: 'James', last: 'Stamplin'}}, 1);
// User "James" will be third because it has the lowest number priority.

usersRef.child("Ash").setWithPriority({name: {first: 'Ash', last: 'Bergler'}}, 20);
// User "Ash" will be forth because it has the lowest number priority 
// after "James"

usersRef.child("Timmy").setWithPriority({name: {first: 'Timmy', last: 'Tables'}}, "xkcd");
// User "Timmy" will be fifth because it has the lowest string priority. 

usersRef.child("John").setWithPriority({name: {first: 'John', last: 'Johnson'}}, "zzz");
// User "John" will be sixth because it has the lowest string priority 
// after "Timmy"

Firebase* usersRef = [[Firebase alloc] initWithUrl:@"https://SampleChat.firebaseIO-demo.com/users/"];

[[usersRef childByAppendingPath:@"Andrew"] setValue:@{@"name": @{@"first": @"Andrew", @"last": @"Gee"}}];
// User "Andrew" will be first because it has no priority.

[[usersRef childByAppendingPath:@"Matt"] setValue:@{@"name": @{@"first": @"Matt", @"last": @"Jones"}}];    
// User "Matt" will be second because it has the same priority as "Andrew"
// and "Andrew" comes lexicographically before "Matt"

[[usersRef childByAppendingPath:@"James"] setValue:@{@"name": @{@"first": @"James", @"last": @"Stamplin"}} andPriority:@1];
// User "James" will be third because it has the lowest number priority.

[[usersRef childByAppendingPath:@"Ash"] setValue:@{@"name": @{@"first": @"Ash", @"last": @"Bergler"}} andPriority:@20];
// User "Ash" will be forth because it has the lowest number priority 
// after "James"

[[usersRef childByAppendingPath:@"Timmy"] setValue:@{@"name": @{@"first": @"Timmy", @"last": @"Tables"}} andPriority:@"xkcd"];
// User "Timmy" will be fifth because it has the lowest string priority. 

[[usersRef childByAppendingPath:@"John"] setValue:@{@"name": @{@"first": @"John", @"last": @"Johnson"}} andPriority:@"zzz"];
// User "John" will be sixth because it has the lowest string priority 
// after "Timmy"

Firebase usersRef = new Firebase("https://SampleChat.firebaseIO-demo.com/users/");

nameRef.child("Andrew").setValue(andrewData);
// User "Andrew" will be first because it has no priority.

nameRef.child("Matt").setValue(mattData);
// User "Matt" will be second because it has the same priority as "Andrew"
// and "Andrew" comes lexicographically before "Matt"

nameRef.child("James").setValue(jamesData, 1);
// User "James" will be third because it has the lowest number priority.

nameRef.child("Ash").setValue(ashData, 20);
// User "Ash" will be forth because it has the lowest number priority 
// after "James"

nameRef.child("Timmy").setValue(timmyData, "xkcd");
// User "Timmy" will be fifth because it has the lowest string priority. 

nameRef.child("John").setValue(johnData, "zzz");
// User "John" will be sixth because it has the lowest string priority 
// after "Timmy"

Note that number priorities are stored and ordered as IEEE 754 double-precision floating-point numbers. Names are always stored as strings and are treated as numeric only when they can be parsed as a 32-bit integer.

Reading Ordered Data

Reading ordered data from your Firebase is simple because the ordering is done automatically. Your Child Added/Moved/Changed will be called in the correct order.

Firebase provides the name of the previous child in callbacks for any Child Added/Moved/Changed events. This parameter tells you where the new / modified child fits within the ordered data. If no child exists before the given child, or if your query does not include any earlier results, the previous child will be null.

Continuing the example from above:

// Assuming your user list was created by the first example, this will output:
//   "User Andrew has entered the chat and should appear at the beginning"
//   "User Matt has entered the chat and should appear after Andrew"
//   "User James has entered the chat and should appear after Matt"
//   "User Ash has entered the chat and should appear after James"
//   "User Timmy has entered the chat and should appear after Ash"
//   "User John has entered the chat and should appear after Timmy" 

 var usersRef = new Firebase('https://SampleChat.firebaseIO-demo.com/users/');
 usersRef.on('child_added', function(snapshot, prevChildName) {
   var userName, userData, where;

   userName = snapshot.name();
   userData = snapshot.val();

   if (prevChildName === null) {
     where = 'at the beginning';
   } else {
     where = 'after ' + prevChildName;
   }
   alert('User ' + userName + ' has entered the chat and should appear ' + where);
 });

 usersRef.on('child_moved', function(snapshot, prevChildName) {
   var userName, userData, where;

   userName = snapshot.name()
   userData = snapshot.val();

   if (prevChildName === null) {
     where = 'at the beginning';
   } else {
     'after ' + prevChildName;
   }
   alert('User ' + userName + ' should now appear ' + where);
 });

// Assuming your user list was created by the first example, this will output:
//   "User Andrew has entered the chat and should appear at the beginning"
//   "User Matt has entered the chat and should appear after Andrew"
//   "User James has entered the chat and should appear after Matt"
//   "User Ash has entered the chat and should appear after James"
//   "User Timmy has entered the chat and should appear after Ash"
//   "User John has entered the chat and should appear after Timmy" 

Firebase* userRef = [[Firebase alloc] initWithUrl:@"https://SampleChat.firebaseIO-demo.com/users/"];
[userRef observeEventType:FEventTypeChildAdded andPreviousSiblingNameWithBlock:^(FDataSnapshot *snapshot, NSString *prevName) {
    NSString *userName = snapshot.name;
    NSDictionary *userData = snapshot.value;
    NSString* where = (prevName == nil) ? @"at the beginning" : [NSString stringWithFormat:@"after %@", prevName];
    NSLog(@"User %@ has entered the chat and should appear %@", userName, where);
}];

[userRef observeEventType:FEventTypeChildMoved andPreviousSiblingNameWithBlock:^(FDataSnapshot *snapshot, NSString *prevName) {
    NSString *userName = snapshot.name;
    NSDictionary *userData = snapshot.value;
    NSString* where = (prevName == nil) ? @"at the beginning" : [NSString stringWithFormat:@"after %@", prevName];
    NSLog(@"User %@ should now appear %@", userName, where);
}];

// Assuming your user list was created by the first example, this will output:
//   "User Andrew has entered the chat and should appear at the beginning"
//   "User Matt has entered the chat and should appear after Andrew"
//   "User James has entered the chat and should appear after Matt"
//   "User Ash has entered the chat and should appear after James"
//   "User Timmy has entered the chat and should appear after Ash"
//   "User John has entered the chat and should appear after Timmy" 

Firebase userRef = new Firebase("https://SampleChat.firebaseIO-demo.com/users/");
userRef.addChildEventListener(new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot snapshot, String previousChildName) {
        String userName = snapshot.getName();
        GenericTypeIndicator<Map<String, Object>> t = new GenericTypeIndicator<Map<String, Object>>() {};
        Map<String, Object> userData = snapshot.getValue(t);
        String where = previousChildName == null ? "at the beginning" : "after " + previousChildName;
        System.out.println("User " + userName + " has entered the chat and should appear " + where);
    }

    @Override public void onChildChanged(DataSnapshot snapshot, String previousChildName) { }

    @Override public void onChildRemoved(DataSnapshot snapshot) { }

    @Override
    public void onChildMoved(DataSnapshot snapshot, String previousChildName) {
        String userName = snapshot.getName();
        GenericTypeIndicator<Map<String, Object>> t = new GenericTypeIndicator<Map<String, Object>>() {};
        Map<String, Object> userData = snapshot.getValue(t);
        String where = previousChildName == null ? "at the beginning" : "after " + previousChildName;
        System.out.println("User " + userName + " should now appear " + where);
    }

    @Override public void onCancelled() { }
});

Inserting Ordered Data

Once you understand how your data is ordered in your Firebase, inserting data at any position becomes simple.

Continuing the examples from above, if you want to add a new user between "James" and "Ash" we need to create a new child with a priority between of 1 and 20.

// Add user "Pete" and set a priority betwen 1 and 20 so he is shown between "James" and "Ash"
var peteRef = new Firebase('https://SampleChat.firebaseIO-demo.com/users/Pete');
peteRef.setWithPriority({name: {first: 'Pete', last: 'Wolo'}}, 10);

// Add user "Pete" and set a priority betwen 1 and 20 so he is shown between "James" and "Ash"
Firebase* peteRef = [[Firebase alloc] initWithUrl:@"https://SampleChat.firebaseIO-demo.com/users/Pete"];
[peteRef setValue:@{@"name": @{@"first": @"Pete", @"last": @"Wolo"}} andPriority:@10];

// Add user "Pete" and set a priority betwen 1 and 20 so he is shown between "James" and "Ash"
Map<String, Object> peteData = new HashMap<String, Object>();
Map<String, Object> peteName = new HashMap<String, Object>();
peteName.put("first", "Pete");
peteName.put("last", "Wolo");
peteData.put("name", peteName);
double petePriority = 10.0;

Firebase peteRef = new Firebase("https://SampleChat.firebaseIO-demo.com/users/Pete");
peteRef.setValue(peteData, petePriority);

By default, the priority is set to null every time a Firebase location is written to. This means that if a priority has been set at a location, future writes that do not specify a priority will set the priority back to null. Also, setting a priority will only have an effect if data exists at the specified Firebase location. If no data exists, the priority will be ignored.

Priorities can also be set using the REST API. See Writing Priorities from the REST API for more information.

Next Steps

Now that you understand how data is ordered, you can start querying your data:


Have a suggestion to improve the documentation on this page? Tell us!