1

Given a Firebase node lines filled with unique-ID children (from push() operations), such as this:

Firebase--
  --lines
    --K3qx02jslkdjNskjwLDK
    --K3qx23jakjdz9Nlskjja
    --K3qxRdXhUFmEJdifOdaj
    --etc...

I want to be able to delete all children of lines except the most recently added 200 (or 100, or whatever). Basically this is a cleanup operation. Now I know I could do this by grabbing a snapshot of all children of lines on the client side, counting the entries, then using an endsAt(totalChildren-numToKeep) to grab the relevant data and run remove(). But I want to avoid grabbing all that data to the client.

Is there an alternative to my idea above?

mix
  • 6,943
  • 15
  • 61
  • 90

1 Answers1

5

Keep the most recent N items, is one of the trickier use-cases to implement. If you have any option to change it into "keep items from the past N hours", I recommend going that route.

The reason the use-case is tricky, is that you're counting items and Firebase does (intentionally) not have any count-based operations. Because of this, you will need to retrieve the first N items to know which item is N+1.

ref.child('lines').once('value', function(snapshot) {
  if (snapshot.numChildren() > MAX_COUNT) {
    var childCount = 0;
    var updates = {};
    snapshot.forEach(function (child) {
      if (++childCount < snapshot.numChildren() - MAX_COUNT) {
        updates[child.key()] = null;
      }
    });
    ref.child('lines').update(updates);
  }
});

A few things to note here:

  • this will download all lines
  • it performs a single update() call to remove the extraneous lines

One way to optimize this (aside from picking a different/time-based truncating strategy) is to keep a separate list of the "line ids".

lineids
  --K3qx02jslkdjNskjwLDK
  --K3qx23jakjdz9Nlskjja
  --K3qxRdXhUFmEJdifOdaj

So you'll still keep the data for each line in lines, but also keep a list of just the ids. The code to then delete the extra ones then becomes:

ref.child('lineids').once('value', function(snapshot) {
  if (snapshot.numChildren() > MAX_COUNT) {
    var childCount = 0;
    var updates = {};
    snapshot.forEach(function (child) {
      if (++childCount < snapshot.numChildren() - MAX_COUNT) {
        updates['lineids/'+child.key()] = null;
        updates['lines/'+child.key()] = null;
      }
    });
    ref.update(updates);
  }
});

This last snippet is slightly more involved, but prevents from having to download all lines data by just downloading the line ids.

There are many variations you can choose, but I hope this serves as enough inspiration to get started.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807