Szymon Kołodziejczak
Szymon Kołodziejczak

Reputation: 23

asynchronous reading db returning collection

I'm tryin to achieve a function which will return all rooms of specific user. I'm working with firebase and to get a specific room I wrote this function:

Db.prototype.getRoom = function (roomUid){

 return new Promise(function(resolve, reject) {

    firebase.database().ref('rooms/' + roomUid).once('value').then(function(snapshot){
      resolve(snapshot.val());
    })
 });
}

Here is my problem - I need to download all rooms before returning the array. I've tried:

Db.prototype.getUserRooms = function(user){

     var rooms = [];

      firebase.database().ref('users/' + user.uid + '/rooms')
      .once('value').then(function(snapshot){

        var roomsIds = snapshot.val() || []; //array of rooms ids

        for(var i = 0; i < roomsIds.length; i++){
          Db.prototype.getRoom(roomsIds[i]).then(function(room){
            rooms.push(room);
          });
        } 

        return rooms;

      });
 }

Thanks for any help

Upvotes: 2

Views: 74

Answers (1)

jfriend00
jfriend00

Reputation: 707218

You have to do a couple things to make this work.

First, when you use a for loop to retrieve a bunch of async values, you have to collect all the promises and use Promise.all() to wait for all those async operations to be done.

Second, when you have a promise inside of a .then() handler, you need to return that promise from the .then() handler to chain it together.

Third, when you want to call a method from within another method, you need to call it on the instance of your object, not directly on the prototype.

// return the inner promise directly rather than wrap in a new promse
Db.prototype.getRoom = function (roomUid){
    return firebase.database().ref('rooms/' + roomUid).once('value').then(function(snapshot){
      // make the `.val()` result be the fulfilled value of the promise
      return snapshot.val();
    })
 });
}

Db.prototype.getUserRooms = function(user){
     var self = this;
     return firebase.database().ref('users/' + user.uid + '/rooms').once('value').then(function(snapshot){
        var roomsIds = snapshot.val() || []; //array of rooms ids
        return Promise.all(roomsIds.map(function(roomID) {
            return self.getRoom(roomID);
        }));
    });
 }

Them, I'm still a bit confused why you're calling methods directly on the prototype such as Db.prototype.getRoom(). Usually, when using object oriented Javascript, you would call methods on an instance of the db object, not directly on the prototype. I've modified getUserRooms() to work this way, calling .getRoom() on the instance.

Then, usage would be like this:

 // assumes mydb is an instance of your Db object

mydb.getUserRooms(someUser).then(function(rooms) {
    // rooms is an array of rooms
    console.log(rooms);
});

Upvotes: 2

Related Questions