24

I'm trying to create simple notification system for my site admin, and I need to send only real-time messages to every admin user. But when I use firebase it loads old data on every page, and user see all messages from database. If I set limit(1) user will see last notification on every page reloading:

var eventsList = new Firebase('https://*****-messages.firebaseio.com/');

eventsList.on('child_added', function(message) {
    var message = message.val();
    $.notification(message.message);
});

How I can load only new messages, without old notification history?

Cœur
  • 37,241
  • 25
  • 195
  • 267
inlanger
  • 2,904
  • 4
  • 18
  • 30
  • 1
    As of Firebase 2.x, there are now some faster ways to accomplish this using queries. See alternate answer for [How to discard initial data in Firebase DB](http://stackoverflow.com/a/27693310/394010) – Kato Jan 16 '15 at 16:08
  • Since the common use case for this question is creating a message queue, the best answer is to use a [message queue strategy](https://github.com/firebase/firebase-work-queue), where events are added and deleted from a queue, and not bother with this added complexity. Please consider that route before any of the answers below – Kato Jan 31 '15 at 17:41

2 Answers2

39

This is by design, in a real-time system there is no concept of the "latest" data because it's always changing. However, if you want to only display items added to the list after the page has loaded, you can do the following:

var newItems = false;
var eventsList = new Firebase('https://*****-messages.firebaseio.com/');

eventsList.on('child_added', function(message) {
  if (!newItems) return;
  var message = message.val();
  $.notification(message.message);
});
eventsList.once('value', function(messages) {
  newItems = true;
});
Anant
  • 7,408
  • 1
  • 30
  • 30
  • 11
    What if the existing list is huge. The callback for child added will be called for each of them. This could cause following problems: 1. It may keep my UI thread busy handling all the callbacks 2. Unnecessary consumption of bandwidth in downloading the data 3. On a flaky connection, it may take lot of time for the initialization process 4. If i have another firebase reference monitoring changes to some other branch, it will not receive callbacks until the child added operation is done for this ref ... Am i correct?? – Kartik Sep 14 '13 at 06:53
  • 2
    The "if (!newItems) return;" check should be right at the beginning so all the initial data will be ignored and should be pretty fast. If you don't actually want to download the data, it's best to use limits/queries to limit the amount of data to exactly what you want. – Anant Sep 16 '13 at 21:13
  • one issue is that updates on a second browser will not come in, since `newItems` will be `false` – Patrioticcow Nov 28 '14 at 08:18
  • 4
    Could you clarify why `once` fires after `on`? From reading it, as they are both async it appears that this is just a race condition. – Gruff McGruff Nov 12 '15 at 17:25
  • @GruffMcGruff I suppose adding the 'child_added' event listener inside the 'value' listener would solve the problem, right? I mean this: `eventsList.once('value', function(messages) { // Do stuff for all messages // Now (and only now), add the 'child_added' listener eventsList.on('child_added', function(message) { var message = message.val(); $.notification(message.message); }); }); ` – user2078023 Feb 22 '17 at 11:03
  • @GruffMcGruff the `once` fires after `on` only because it is added after. If you swapped places and put the `once` higher up in the script it would trigger first.Both listeners trigger a download of the whole list of data. The differences between `on` and `once` is that `on` is retriggered when data changes. The difference between `child_added` and `value` is that `child_added` is triggered for each individual item. – Jacob Wright Jun 29 '17 at 00:26
  • @user2078023 It is better to add the listeners as done in the answer. If you were to add `on` listener inside the `once` listener you will still get all the messages you got in the `once`. – Jacob Wright Jun 29 '17 at 00:29
6

I would comment on the above, but due to reputation I cannot, so hoping this is adequate and this is to address the last comment by Gruff McGruff.

Once fires after because you want to break out of the loop of grabbing all child items. Once that loops is broken, you'll set the newItems variable to true, and then it will be able to get all new children after that.

If you fired it before, it would defeat the purpose and grab all child items regardless because you'll set the newItems variable immediately.

Also, I've used this approach and it works well.