5

I have a node in Firebase getting continually updated with information from a logfile. The node is lines/ and each child of lines/ is from a post() so it has a unique ID.

When a client first loads, I want to be able to grab the last X number of entries. I expect I'll do this with once(). From then on, however, I want to use an on() with child_added so that I get all new data. However, child_added gets all data stored in the Firebase and, after the initial setup, only want the new stuff.

I see that I can add a limitToLast() on the on(), but, if I say limitToLast(1) and a flood of entries come in, will my app still get all the new entries? Is there some other way to do this?

mix
  • 6,943
  • 15
  • 61
  • 90
  • If my answer solved your problem, would you mind marking it as the solution? If not let me know what else is needed. – David East Nov 26 '15 at 21:46

4 Answers4

8

You need to include a timestamp property and run a query.

// Get the current timestamp
var now = new Date().getTime();
// Create a query that orders by the timestamp
var query = ref.orderByChild('timestamp').startAt(now);
// Listen for the new children added from that point in time
query.on('child_added', function (snap) { 
  console.log(snap.val()
});

// When you add this new item it will fire off the query above
ref.push({ 
  title: "hello", 
  timestamp: Firebase.ServerValue.TIMESTAMP 
});

The Firebase SDK has methods for ordering, orderByChild() and methods for creating a range startAt(). When you combine the two you can limit what comes back from Firebase.

David East
  • 31,526
  • 6
  • 67
  • 82
  • 5
    The problem in your solution is the `new Date().getTime()` may not get the right timestamp if the client device is not be synchronized. – Bagusflyer Nov 17 '16 at 01:54
1

I think there is a problem in @David East's solution. He is using the local timestamp which may cause problem if the time is not accurate in client device. Here is my suggested solution (iOS Swift):

  • Using observeSingleEvent to get the complete data set
  • Then returned it in reversed order by reversed()
  • Get the last timestamp by for example data[0].timestamp
  • Using queryStarting for timestamp

     self._dbref.queryOrdered(byChild: "timestamp").queryStarting(atValue: timestamp+1)
         .observe(.childAdded, with: {
            snapshot in
            print(snapshot.value)
      })
    
Bagusflyer
  • 12,675
  • 21
  • 96
  • 179
0

You have the right idea. child_added should be called only for the new nodes. Without source code it's hard to tell why you get all the data in your child_added event.

You can check the chat demo app to see how they load new chat messages. The use case sounds similar.

https://github.com/firebase/firechat/blob/master/src/js/firechat.js#L347

monkbroc
  • 808
  • 9
  • 13
  • 1
    The `child_added` event fires off for all data and *then* the new nodes. So he'll need to use a combination of a timestamp and a query to get only the latest nodes after a point. – David East Nov 24 '15 at 04:48
0

Here's temporary but quick solution:

// define a boolean
var bool = false;

// fetch the last child nodes from firebase database
ref.limitToLast(1).on("child_added", function(snap) {
    if (bool) {
        // all the existing child nodes are restricted to enter this area
        doSomething(snap.val())
    } else {
        // set the boolean true to doSomething with newly added child nodes
        bool = true;
    }
});

Disadvantage: It will load all the child nodes.

Advantage: It will not process existing child nodes but just the newly added child nodes.

limitToLast(1) will do the work.

Sowmay Jain
  • 865
  • 1
  • 10
  • 21