Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Firebase, how can I query the most recent 10 child nodes?

Tags:

ios

firebase

I'm using childByAutoId() to generate my children. Each child looks like:

{
    user_id: 1
}

I'd like to get the last 10 most recently added, sorted by time DESC. What's the easiest way to do this?

like image 655
TIMEX Avatar asked Apr 13 '16 05:04

TIMEX


People also ask

How do I order children in a firebase query?

If you care to receive your data from Firebase in the specified order, make sure to use ref.on (‘child_added’, callback), because it will be called once for each existing child, and it will be called in order. So aggregated your children into an array manually, and you’ll have ordered children! An orderBy* parameter is required for any query.

How do I retrieve specific data from a Firebase Database?

With Firebase database queries, you can selectively retrieve data based on various factors. To construct a query in your database, you start by specifying how you want your data to be ordered using one of the ordering functions: orderByChild(), orderByKey(), or orderByValue().

What is an asynchronous listener in Firebase?

Asynchronous listeners: Data stored in a Firebase Realtime Database is retrieved by attaching an asynchronous listener to a database reference. The listener is triggered once for the initial state of the data and again anytime the data changes. An event listener may receive several different types of events.

How do I append a list to a list in Firebase?

Append to a list of data. Use the push() method to append data to a list in multiuser applications. The push() method generates a unique key every time a new child is added to the specified Firebase reference.


2 Answers

The answer is that you need to use a bit of reverse logic, and also store a timestamp key:value pair within each node as a negative value. I omitted the user_id: 1 to keep the answer cleaner.

Here's the Firebase structure

"test" : {
    "-KFUR91fso4dEKnm3RIF" : {
      "timestamp" : -1.46081635550362E12
    },
    "-KFUR9YH5QSCTRWEzZLr" : {
      "timestamp" : -1.460816357590991E12
    },
    "-KFURA4H60DbQ1MbrFC1" : {
      "timestamp" : -1.460816359767055E12
    },
    "-KFURAh15i-sWD47RFka" : {
      "timestamp" : -1.460816362311195E12
    },
    "-KFURBHuE7Z5ZvkY9mlS" : {
      "timestamp" : -1.460816364735218E12
    }
  }

and here's how that's written out to Firebase; I just used a IBAction for a button to write out a few nodes:

let testRef = self.myRootRef.childByAppendingPath("test")

let keyRef = testRef.childByAutoId()

let nodeRef = keyRef.childByAppendingPath("timestamp")

let t1 = Timestamp

nodeRef.setValue( 0 - t1) //note the negative value

and the code to read it in

    let ref = self.myRootRef.childByAppendingPath("test")
    ref.queryOrderedByChild("timestamp").queryLimitedToFirst(3).observeEventType(.ChildAdded, withBlock: { snapshot in
        print("The key: \(snapshot.key)") //the key
    })

and I declared a little function to return the current Timestamp

var Timestamp: NSTimeInterval {
    return NSDate().timeIntervalSince1970 * 1000
}

and the output

The key: -KFURBHuE7Z5ZvkY9mlS
The key: -KFURAh15i-sWD47RFka
The key: -KFURA4H60DbQ1MbrFC1

As you can see, they are in reverse order.

Things to note:

  1. Writing out your timestamp as negative values
  2. When reading in use .queryLimitedToFirst instead of last.

On that note, you can also just read the data as usual and add it to an Array then then sort the array descending. That puts more effort on the client and if you have 10,000 nodes may not be a good solution.

like image 61
Jay Avatar answered Oct 27 '22 07:10

Jay


I'm assuming your data actually looks like this:

someDataSet: {
    longUID-1: {
        timeCreated: 9999999999, // (seconds since the javascript epoch)
        user_id: 1
    },
    longUID-2: {
        timeCreated: 1111111111,
        user_id: 2
    },
    longUID-3: {
        timeCreated: 3141592653,
        user_id: 3
    }
}

You could automate that by calling Firebase.push({user_id: ###, timeCreated: ###}) multiple times in a for loop or any other method. Maybe you're adding news stories to a webpage, but you only want your user to see the most current stories--- IDK. But the answer to your question is to use Firebase's ref.orderByChild() and ref.limitToLast().

var ref = new Firebase("<YOUR-FIREBASE-URL>.firebaseio.com/someDataSet"); 
    //the "/someDataSet" comes from the arbitrary name that I used up above

var sortedRef = ref.orderByChild('timeCreated');
    //sort them by timeCreated, ascending

sortedRef.limitToLast(2).on("child_added", function(snapshot){
    var data = snapshot.val();

    console.log(data);

    /* do something else with the data */
});

//The console would look like this

// Object {timeCreated: 9999999999, user_id: 1}
// Object {timeCreated: 3141592653, user_id: 3}

This happened because the program took the child with the greatest timeCreated value first and then the second greatest (value) second... Also note, the longUID means nothing when you sort them by child and neither do the other values (user_id in this case)

Here is the documentation for:

  • Firebase .push() method (Sorry, I'm not allowed to post this link- I dont have enough reputation)
  • Firebase .orderByChild method
  • And also, Firebase .limitToLast method
like image 41
Frozenfrank Avatar answered Oct 27 '22 08:10

Frozenfrank