0

I would like to check recursively if a node exist in Firebase (created by cloudfunction), I tried many things but I'm a bit lost between promises, callbacks etc and I can't make it work.

Here is what I tried (in a auth service) :

checkifExist(userId:string){
  const self=this;
  firebase.database().ref('/users/'+userId).once('value', function(snap) {
      return true;
  }, function(error) {
      console.log("user not yet created by CF :"+error);

      // wait 2 seconds before to try again
      setTimeout(() =>{
          self.checkifExist(userId);
      },2000);
  });

and I call it in a component with :

if(this.auth.checkifExist(userId)){
  // code if success
}

Problem :

the code if success is never executed, because :

this.auth.checkifExist(userId) is undefined

why? Any idea?

Julien
  • 3,743
  • 9
  • 38
  • 67
  • To check if a node exists you could do like that: `firebase.database().ref('/users/' + userId).once('value', function(snap) { if (snapshot.val() !== null) { //node with id userId exists under node user } else { //node with id userId DOES NOT exist under node user } });` Not 100% sure how to call it recursively though, since `once` returns a promise. – Renaud Tarnec Apr 27 '18 at 12:58

2 Answers2

3

Self-invoking a function that is listening for data in the Firebase Database is an anti-pattern. It is not needed, because Firebase listeners can already listen for data continuously, if you use the on() method.

The simplest way to do what you want is with a callback:

waitForUserData(userId:string, callback){
  var ref = firebase.database().ref('/users/'+userId);
  ref.on('value', function(snap) {
    if (snap.exists()) {
      ref.off('value'); // stop listening
      callback();
    }
  }, function(error) {
    // we don't have permission to read
    throw error;
  });
}

You invoke this as:

this.auth.waitForUserData(userId, function() {
  // code if success
});

Things I changed:

  • Pass in a callback, that the function will call once a value has been read from the database.
  • You seem to assume that the error handler will be called if no value exists, which is not true. If no value exists, the callback will be called with an empty snapshot.
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
1

As said in my comment, I am not 100% sure how to call the asynchronous once method recursively, but based on multiple, sequential fetch() Promise I will give a try:

checkifExist(userId:string){
  const self=this;
  return firebase.database().ref('/users/'+userId).once('value', function(snap) {
    if (snapshot.val() === null) {
       return false;
    } else {
       return true;
    }
  })
  .then(function(response) {
    if (response) {
       return true;
    } else {
       self.checkifExist(userId); 
    }
  })
  .catch(function(err) {
     console.log('error: ' + err);
     //.....
  });
}

Note that once returns a promise, see https://firebase.google.com/docs/reference/js/firebase.database.Reference#once

Renaud Tarnec
  • 79,263
  • 10
  • 95
  • 121