Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

child_added gets triggered after remove

I've created this handler to watch for new children being created. This little trick stops the child_added event from triggering my code on each page load. Instead it only gets triggered when something is actually added.

  // Listen for new rooms being created
  var first_room_added_after_load = true;
  this._roomRef.endAt().limit(1).on('child_added', function(snapshot){
      if (first_room_added_after_load) { // we want to skip the first room, because it will already exist
          first_room_added_after_load = false;
          return;
      }
      else {
          this._onCreateRoom(snapshot);
      }
  }, this);

That said, when I call remove() on a node in _roomRef then child_added is triggered for a node that already exists. Any hints as to why, and how to stop it?

I should also mention this only seems to happen if I remove something that was created after something else already in the list. If I remove the older items first, then child_added is not triggered.

like image 694
user128638 Avatar asked Mar 19 '23 18:03

user128638


1 Answers

You seem to think the endAt() uses a timestamp for comparison, so that it only returns new children. But that's simply not how it works. From the Firebase documentation for endAt:

If no arguments are provided, the ending point will be the end of the data.

With your code:

this._roomRef.endAt().limit(1)

You're creating a query that is set to always return a single child. The condition is that the child was created after you created the query.

A query is like a sliding window over the child nodes in your Firebase ref: it will always contain (at most) one child, a child that was created after you created your query.

Example

Say you have these children when you create the query:

child1
child2
child3 <!-- last child present when creating the endAt() query -->

By using endAt query will be "rooted" after child3. So it will not fire any events for child1, child2 and child3.

Say you add a new child:

child1
child2
child3 <!-- last child present when creating the endAt() query -->
child4

The query will a child_added event for child4.

Now if we add another child:

child1
child2
child3 <!-- last child present when creating the endAt() query -->
child4
child5

The query will fire a child_removed for child4 and child_added for child5. Note that child4 was not actually removed from your Firebase, it just disappeared from the query results (since you asked to limit the number of results to just one).

When we now remove the latest child, we end up with:

child1
child2
child3 <!-- last child present when creating the endAt() query -->
child4

And the query will fire a child_removed for child5 and child_added for child4. This again comes from the fact that your query is set to always contain (at most) one node that was added after child3.

How to get what you want

It seems like you only want to get child_added once for newly added children. In that case I would not use a limit on the query, but instead I would set the timestamp that the room was created as its priority:

this._roomRef.push({
    /* whatever properties you need for a room */, 
    '.priority': Firebase.ServerValue.TIMESTAMP 
})

Then you can simply start the query at that priority.

this._roomRef.startAt(Date.now()).on('child_added', ...
like image 77
Frank van Puffelen Avatar answered Mar 29 '23 18:03

Frank van Puffelen