2

enter image description here

I want to clean up this userPublic by deleting all of its child node which has isTesting == true. I am using Firebase's cloud function. My approach would be :

const userPublic = admin.database().ref("/userPublic")
const testsInUserPublic = userPublic.orderByChild("isTesting").equalTo(true)
testsInUserPublic.once("value", dataSnapshot => {
    // ???
})
  1. Since I can only call .remove() on reference and not snapshot but to filter the child I want it returns snapshot, how can I get the reference from snapshot? (I would like to know the key XXX-XXX-XXX of each filtered child, so I can concatenate with userPublic and .remove() them one by one)

  2. Also, even if I can get all the references that I want to remove I think deleting them one by one by calling .remove() then wait for promise, then call the next one does not sounds like an optimal way. Are there any way to remove all of them in one go?

  3. If it involves calling .update() on the top userPublic node, I would have to fetch everything, remove the one with isTesting and then put the remaining back for update. This sounds like it is not efficient compared to the filtering way. As eventually the one with .isTesting is only about 5% of all data. Or is this actually the approach everyone is using?

5argon
  • 3,683
  • 3
  • 31
  • 57

1 Answers1

2

You're almost there. All that's left is to create a single multi-location update from the results of your query:

const userPublic = admin.database().ref("/userPublic")
const testsInUserPublic = userPublic.orderByChild("isTesting").equalTo(true)
testsInUserPublic.once("value", snapshot => {
    var updates = {};
    snapshot.forEach(function(child) {
      updates["/userPublic/"+child.key] = null;
    });
    userPublic.update(updates);
})

Doing this with promises would not be too different:

testsInUserPublic.once("value", snapshot => {
    var promises = [];
    snapshot.forEach(function(child) {
      promises.push(child.ref.remove());
    });
    Promise.all(promises); // this returns a promise that resolves once all deletes are done, or that rejects once one of them fails
})

Performance of this will be very similar, since Firebase pipelines the requests over a single connection. See http://stackoverflow.com/questions/35931526/speed-up-fetching-posts-for-my-social-network-app-by-using-query-instead-of-obse/35932786#35932786

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • The ref variable is already at "/userPublic" why do I still need to include "/userPublic" again in the `updates` key? In [here](https://firebase.google.com/docs/database/admin/save-data#section-update) it seems to goes on from the referenced path. – 5argon Aug 08 '17 at 16:50
  • 1
    It does, but I wasn't sure of your path. The important thing to realize is that you can put an entire path in the key, so you can update at any level. Well.. and the fact that writing `null` to a location, removes that path, that's the other important thing. :-) – Frank van Puffelen Aug 08 '17 at 17:32
  • With an entire path in the key, isn't `userPublic.update(updates);` results in double `/userPublic/userPublic/XXX-XXX-XXX` because `userPublic` is already at `/userPublic`? If I use the entire path shouldn't I start from root? – 5argon Aug 08 '17 at 17:36
  • I think it starts from the root, because of the leading `/`. But you're in a perfect position to verify that. – Frank van Puffelen Aug 08 '17 at 17:40
  • Doesn't the "snapshot.ref.remove()" remove the entire "/userPublic"?! Shouldn't it be "child.ref.remove()"? – Martin B Oct 11 '17 at 20:27
  • Woops, indeed that should be `child.ref.remove()`. Thanks for catching! – Frank van Puffelen Oct 11 '17 at 22:23