Promise.all with Firebase DataSnapshot.forEach

13,802

You have to execute the Promise.all after you filled the array with promises, i.e. inside the then callback:

function loadMeetings(city,state) {
    //$('#meetingsTable').empty();
    return ref.child('states').child(state).child(city).once('value').then(function(snapshot) {
        var reads = [];
//      ^^^^^^^^^^^^^^
        snapshot.forEach(function(childSnapshot) {
            var id = childSnapshot.key;
            var promise = ref.child('meetings').child(id).once('value').then(function(snap) {
                // The Promise was fulfilled.
            }, function(error) {
                // The Promise was rejected.
                console.error(error);
            });
            reads.push(promise);
        });
        return Promise.all(reads);
//      ^^^^^^^^^^^^^^^^^
    }, function(error) {
        // The Promise was rejected.
        console.error(error);
    }).then(function(values) { 
        console.log(values); // [snap, snap, snap] 
    });
}
Share:
13,802
Ronnie Royston
Author by

Ronnie Royston

Tulane University (Philosophy '97), Cisco Certified Internetworking Expert (CCIE# 6824), and USPA Master Skydiver (D# 20776).

Updated on June 10, 2022

Comments

  • Ronnie Royston
    Ronnie Royston about 2 years

    I have a couple of HTML select's (dropdowns) that are populated from a Firebase node called "states" (see image below). Upon choosing a city, the below function fires and should retrieve all meetings occurring in that City. There is a separate "meetings" node and each meeting has various key/value pairs such as street, time, etc.

    I (think that I) want to use Promise.all because I want to do a Firebase read (a .once on each meetingID) inside the DataSnapshot.forEach. Below does not work.

    function loadMeetings(city,state){
        //$('#meetingsTable').empty();
        var reads = [];
        ref.child('states').child(state).child(city).once('value').then(function(snapshot) {
            snapshot.forEach(function(childSnapshot) {
                var id = childSnapshot.key();
                var dfd = ref.child('meetings').child(id).once('value').then(function(snap) {
                    // The Promise was fulfilled.
                }, function(error) {
                    // The Promise was rejected.
                    console.error(error);
                });
                reads.push( dfd );
            });       
        }, function(error) {
            // The Promise was rejected.
            console.error(error);
        });
    
        Promise.all(reads).then(function(values) { 
          console.log(values); // [snap, snap, snap] 
        });
    }
    

    {
      "geofire" : {
        "25dbab9c-8e4e-45ce-a69b-8641b6579560" : {
          ".priority" : "9q5cc9ye4w",
          "g" : "9q5cc9ye4w",
          "l" : [ 34.0677809, -118.4016105 ]
        },
        "3d2c7948-16e5-466c-b0d8-0a9e24ed7529" : {
          ".priority" : "7zzzzzzzzz",
          "g" : "7zzzzzzzzz",
          "l" : [ 0, 0 ]
        },
        "3fc846d4-7e55-4134-a0f5-9393aaf02269" : {
          ".priority" : "dhyy1zhnu1",
          "g" : "dhyy1zhnu1",
          "l" : [ 27.8130538, -80.42524100000003 ]
        },
        "5952bd9f-8438-44b0-addb-a5b806dab5da" : {
          ".priority" : "9vw1zzv421",
          "g" : "9vw1zzv421",
          "l" : [ 31.288082, -92.46505450000001 ]
        },
        "7001c8a7-c4f0-44ba-a4fc-2dba32097cc6" : {
          ".priority" : "9vqe68qs06",
          "g" : "9vqe68qs06",
          "l" : [ 30.1046126, -91.99056969999998 ]
        },
        "ecb350d6-6664-4f95-9c1c-2fd1d2f11a40" : {
          ".priority" : "9vrk9tstc9",
          "g" : "9vrk9tstc9",
          "l" : [ 30.353474, -90.98251599999998 ]
        }
      },
      "markup" : {
        "addMeeting" : "<form class=\"outline\"><div class=\"row\"><h1 class=\"blue topTitle col-xs-10 col-xs-offset-1 col-md-4 col-md-offset-4\">New Meeting</h1></div><br><div class=\"form-group row\"><div class=\"col-xs-10 col-xs-offset-1 col-md-3 col-md-offset-2\"> <input type=\"text\" class=\"form-control\" id=\"meetingName\" placeholder=\"Meeting Name\"> </div><div class=\"col-xs-10 col-xs-offset-1 col-md-4 col-md-pull-1\"> <input type=\"text\" class=\"form-control\" id=\"meetingStreet\" placeholder=\"Street\" required> </div></div><div class=\"form-group row\"><div class=\"col-xs-10 col-xs-offset-1 col-md-3 col-md-offset-2\"> <input type=\"text\" class=\"form-control\" id=\"meetingCity\" placeholder=\"City\" required> </div><div class=\"col-xs-10 col-xs-offset-1 col-md-2 col-md-pull-1\"> <select class=\"form-control c-select\" id=\"meetingState\" required><option>Alabama </option><option>Alaska</option><option>Arizona</option><option>Arkansas</option><option>California</option><option>Colorado</option><option>Connecticut</option><option>Delaware</option><option>Florida</option><option>Georgia</option><option>Hawaii</option><option>Idaho</option><option>Illinois</option><option>Indiana</option><option>Iowa</option><option>Kansas</option><option>Kentucky</option><option>Louisiana</option><option>Maine</option><option>Maryland</option><option>Massachusetts</option><option>Michigan</option><option>Minnesota</option><option>Mississippi</option><option>Missouri</option><option>Montana</option><option>Nebraska</option><option>Nevada</option><option>New Hampshire</option><option>New Jersey</option><option>New Mexico</option><option>New York</option><option>North Carolina</option><option>North Dakota</option><option>Ohio</option><option>Oklahoma</option><option>Oregon</option><option>Pennsylvania</option><option>Rhode Island</option><option>South Carolina</option><option>South Dakota</option><option>Tennessee</option><option>Texas</option><option>Utah</option><option>Vermont</option><option>Virginia</option><option>Washington</option><option>West Virginia</option><option>Wisconsin</option><option>Wyoming</option></select></div><div class=\"col-xs-10 col-xs-offset-1 col-md-2 col-md-pull-2\"> <input type=\"text\" class=\"form-control\" id=\"meetingZip\" placeholder=\"ZIP\" required> </div></div><div class=\"form-group row\"><div class=\"col-xs-5 col-xs-offset-1 col-md-2 col-md-offset-2\"> <input type=\"text\" class=\"form-control\" id=\"latitude\" placeholder=\"latitude\" disabled> </div><div class=\"col-xs-5 col-md-2 pull-left\"> <input type=\"text\" class=\"form-control\" id=\"longitude\" placeholder=\"longitude\" disabled> </div></div><div class=\"form-group row\"><div class=\"col-xs-10 col-xs-offset-1 col-md-2 col-md-offset-2\"><select class=\"form-control c-select\" id=\"weekday\"><option>Sunday</option><option>Monday</option><option>Tuesday</option><option>Wednesday</option><option>Thursday</option><option>Friday</option><option>Saturday</option></select></div><div class=\"col-xs-10 col-xs-offset-1 col-md-3 col-md-pull-1\"><div class=\"form-inline\"><div class=\"form-group\"><select class=\"form-control c-select\" id=\"hour\"><option>1</option><option>2</option><option>3</option><option>4</option><option>5</option><option>6</option><option>7</option><option>8</option><option>9</option><option>10</option><option>11</option><option>12</option></select><select class=\"form-control c-select\" id=\"minute\"><option>:00</option><option>:15</option><option>:30</option><option>:45</option></select><select class=\"form-control c-select\" id=\"timeframe\"><option>AM</option><option>PM</option></select></div></div></div></div><div class=\"form-group row\"><div class=\"col-xs-10 col-xs-offset-1 col-md-4 col-md-offset-2\"> <label class=\"radio-inline c-input c-radio\"> <input type=\"radio\" name=\"meetingType\" id=\"openMeeting\"> <span class=\"c-indicator\"></span> Open Meeting </label> <label class=\"radio-inline c-input c-radio\"> <input type=\"radio\" name=\"meetingType\" id=\"closedMeeting\" checked> <span class=\"c-indicator\"></span> Closed Meeting </label> </div></div><div class=\"form-group row\"><div class=\"col-xs-5 col-xs-offset-1 col-md-2 col-md-offset-2\"> <label class=\"c-input c-checkbox\"> <input type=\"checkbox\" id=\"mensOnly\"> <span class=\"c-indicator\"></span> Mens Only </label><br><label class=\"c-input c-checkbox\"> <input type=\"checkbox\" id=\"womensOnly\"> <span class=\"c-indicator\"></span> Womens Only </label><br><label class=\"c-input c-checkbox\"> <input type=\"checkbox\" id=\"childcare\"> <span class=\"c-indicator\"></span> Childcare </label> </div><div class=\"col-xs-5 col-xs-offset-1 col-md-2 col-md-pull-1\"> <label class=\"c-input c-checkbox\"> <input type=\"checkbox\" id=\"meditation\"> <span class=\"c-indicator\"></span> Meditation </label><br><label class=\"c-input c-checkbox\"> <input type=\"checkbox\" id=\"speaker\"> <span class=\"c-indicator\"></span> Speaker </label><br><label class=\"c-input c-checkbox\"> <input type=\"checkbox\" id=\"step\"> <span class=\"c-indicator\"></span> Step </label> </div></div><div class=\"form-group row\"><div class=\"col-xs-5 col-xs-offset-1 col-md-2 col-md-offset-2\"> <label class=\"c-input c-checkbox\"> <input type=\"checkbox\" id=\"spanish\"> <span class=\"c-indicator\"></span> Español </label><br><label class=\"c-input c-checkbox\"> <input type=\"checkbox\" id=\"bigBook\"> <span class=\"c-indicator\"></span> Big Book </label><br><label class=\"c-input c-checkbox\"> <input type=\"checkbox\" id=\"discussion\"> <span class=\"c-indicator\"></span> Discussion </label> </div><div class=\"col-xs-5 col-xs-offset-1 col-md-2 col-md-pull-1\"> <label class=\"c-input c-checkbox\"> <input type=\"checkbox\" id=\"tradition\"> <span class=\"c-indicator\"></span> Tradition </label><br><label class=\"c-input c-checkbox\"> <input type=\"checkbox\" id=\"beginner\"> <span class=\"c-indicator\"></span> Beginner </label> </div></div><div class=\"form-group row\"><div class=\"col-xs-5 col-xs-offset-8 col-md-2 col-md-offset-8\"> <input class=\"btn btn-primary\" type=\"submit\" id=\"submit\"></input> </div></div></form>",
        "admin" : "<ul id=\"tabs\" class=\"nav nav-tabs\"> <li class=\"nav-item\"> <a data-toggle=\"tab\" class=\"nav-link active\" href=\"#adminWelcome\" role=\"tab\">Welcome</a> </li><li class=\"nav-item dropdown\"> <a class=\"nav-link dropdown-toggle\" data-toggle=\"dropdown\" href=\"#\" role=\"button\" aria-haspopup=\"true\" aria-expanded=\"false\">Meetings</a> <div class=\"dropdown-menu\"> <a data-toggle=\"tab\" class=\"dropdown-item\" href=\"#addMeeting\">Add</a> <a data-toggle=\"tab\" class=\"dropdown-item\" href=\"#manageMeeting\">Manage</a> </div></li><li class=\"nav-item dropdown\"> <a class=\"nav-link dropdown-toggle\" data-toggle=\"dropdown\" href=\"#\" role=\"button\" aria-haspopup=\"true\" aria-expanded=\"false\">Users</a> <div class=\"dropdown-menu\"> <a data-toggle=\"tab\" class=\"dropdown-item\" href=\"#addUser\">Add</a> <a data-toggle=\"tab\" class=\"dropdown-item\" href=\"#manageUser\">Manage</a> </div></li></ul> <div class=\"tab-content\"> <div id=\"adminWelcome\" class=\"tab-pane fade in active\" role=\"tabpanel\"> <h3 class=\"topTitle\">Welcome.</h3><div class=\"loader\"><img src=\"images/loading.gif\"><p class=\"blue\">Running Scripts...</p></div><script>adminInit();</script> </div><div id=\"addMeeting\" class=\"tab-pane fade\" role=\"tabpanel\"><div class=\"loader\"><img src=\"images/loading.gif\"><p class=\"blue\">Running Scripts...</p></div></div><div id=\"manageMeeting\" class=\"tab-pane fade\" role=\"tabpanel\"><div class=\"loader\"><img src=\"images/loading.gif\"><p class=\"blue\">Running Scripts...</p></div></div><div id=\"addUser\" class=\"tab-pane fade\" role=\"tabpanel\"><div class=\"loader\"><img src=\"images/loading.gif\"><p class=\"blue\">Running Scripts...</p></div></div><div id=\"manageUser\" class=\"tab-pane fade\" role=\"tabpanel\"><div class=\"loader\"><img src=\"images/loading.gif\"><p class=\"blue\">Running Scripts...</p></div></div></div>",
        "adminWelcome" : "<p>This is the admin welcome pane</p>",
        "login" : "<div class=\"row topMargin myLogin col-xs-10 col-xs-offset-1 col-md-6 col-md-offset-3\"><br><h1 class=\"\">Log In</h1><br><div class=\"btn-group-vertical\" role=\"group\"><button class=\"btn btn-secondary myButton\" id=\"facebook\"><img src=\"images/facebook.png\" class=\"middle\" alt=\"Facebook logo\" height=\"24\"> Facebook</button><button class=\"btn btn-secondary myButton\" id=\"google\"><img src=\"images/google.png\" class=\"middle\" alt=\"Google logo\" height=\"24\"> Google</button><button class=\"btn btn-secondary myButton\" id=\"twitter\"><img src=\"images/twitter.png\" class=\"middle\" alt=\"Twitter logo\" height=\"24\"> Twitter</button></div><br><br><br></div>",
        "manageMeeting" : "<form class=\"form-inline outline\"><div class=\"form-group\"><label for=\"ddState\">Filter&nbsp; </label><select class=\"form-control\" id=\"ddState\" disabled></select></div><div class=\"form-group\"><label for=\"ddState\">&nbsp;&nbsp;&nbsp; </label><select class=\"form-control state\" id=\"ddCity\" disabled></select></div></form>"
      },
      "meetings" : {
        "25dbab9c-8e4e-45ce-a69b-8641b6579560" : {
          "author" : "Ron Royston",
          "beginner" : true,
          "bigBook" : true,
          "childcare" : false,
          "city" : "los angeles",
          "day" : "sunday",
          "discussion" : false,
          "hour" : "4",
          "key" : "25dbab9c-8e4e-45ce-a69b-8641b6579560",
          "latitude" : 34.0677809,
          "layer" : "",
          "longitude" : -118.4016105,
          "meditation" : false,
          "meetingOpen" : false,
          "min" : ":00",
          "name" : "highrise",
          "onlyMen" : false,
          "onlyWomen" : true,
          "spanish" : true,
          "speaker" : false,
          "state" : "california",
          "step" : false,
          "street" : "111 rodeo",
          "timeframe" : "pm",
          "timestamp" : 1457470568863,
          "tradition" : true,
          "type" : "",
          "user" : "facebook:196986260658947",
          "zip" : "90210"
        },
        "3d2c7948-16e5-466c-b0d8-0a9e24ed7529" : {
          "author" : "Ron Royston",
          "beginner" : false,
          "bigBook" : false,
          "childcare" : false,
          "city" : "baton rouge",
          "day" : "sunday",
          "discussion" : false,
          "hour" : "1",
          "key" : "3d2c7948-16e5-466c-b0d8-0a9e24ed7529",
          "latitude" : 0,
          "layer" : "",
          "longitude" : 0,
          "meditation" : false,
          "meetingOpen" : false,
          "min" : ":00",
          "name" : "asdf",
          "onlyMen" : false,
          "onlyWomen" : false,
          "spanish" : false,
          "speaker" : false,
          "state" : "louisiana",
          "step" : false,
          "street" : "234 kjhkj",
          "timeframe" : "am",
          "timestamp" : 1457470215505,
          "tradition" : false,
          "type" : "",
          "user" : "facebook:196986260658947",
          "zip" : "70817"
        },
        "3fc846d4-7e55-4134-a0f5-9393aaf02269" : {
          "author" : "Ron Royston",
          "beginner" : false,
          "bigBook" : true,
          "childcare" : true,
          "city" : "miami",
          "day" : "sunday",
          "discussion" : true,
          "hour" : "1",
          "key" : "3fc846d4-7e55-4134-a0f5-9393aaf02269",
          "latitude" : 27.8130538,
          "layer" : "",
          "longitude" : -80.42524100000003,
          "meditation" : false,
          "meetingOpen" : false,
          "min" : ":00",
          "name" : "beach",
          "onlyMen" : false,
          "onlyWomen" : false,
          "spanish" : true,
          "speaker" : false,
          "state" : "florida",
          "step" : false,
          "street" : "120 a1a",
          "timeframe" : "am",
          "timestamp" : 1457470499310,
          "tradition" : false,
          "type" : "",
          "user" : "facebook:196986260658947",
          "zip" : "33101"
        },
        "5952bd9f-8438-44b0-addb-a5b806dab5da" : {
          "author" : "Ron Royston",
          "beginner" : true,
          "bigBook" : false,
          "childcare" : false,
          "city" : "alexandria",
          "day" : "sunday",
          "discussion" : false,
          "hour" : "1",
          "key" : "5952bd9f-8438-44b0-addb-a5b806dab5da",
          "latitude" : 31.288082,
          "layer" : "",
          "longitude" : -92.46505450000001,
          "meditation" : false,
          "meetingOpen" : false,
          "min" : ":00",
          "name" : "howdy",
          "onlyMen" : false,
          "onlyWomen" : false,
          "spanish" : false,
          "speaker" : false,
          "state" : "louisiana",
          "step" : false,
          "street" : "5676 city park",
          "timeframe" : "am",
          "timestamp" : 1457470284850,
          "tradition" : true,
          "type" : "",
          "user" : "facebook:196986260658947",
          "zip" : "71301"
        },
        "7001c8a7-c4f0-44ba-a4fc-2dba32097cc6" : {
          "author" : "Ron Royston",
          "beginner" : false,
          "bigBook" : false,
          "childcare" : false,
          "city" : "lafayette",
          "day" : "sunday",
          "discussion" : false,
          "hour" : "1",
          "key" : "7001c8a7-c4f0-44ba-a4fc-2dba32097cc6",
          "latitude" : 30.1046126,
          "layer" : "",
          "longitude" : -91.99056969999998,
          "meditation" : false,
          "meetingOpen" : false,
          "min" : ":00",
          "name" : "test3",
          "onlyMen" : false,
          "onlyWomen" : false,
          "spanish" : false,
          "speaker" : false,
          "state" : "louisiana",
          "step" : false,
          "street" : "234 kjhkj",
          "timeframe" : "am",
          "timestamp" : 1457470252872,
          "tradition" : false,
          "type" : "",
          "user" : "facebook:196986260658947",
          "zip" : "70500"
        },
        "ecb350d6-6664-4f95-9c1c-2fd1d2f11a40" : {
          "author" : "Ron Royston",
          "beginner" : false,
          "bigBook" : false,
          "childcare" : false,
          "city" : "baton rouge",
          "day" : "sunday",
          "discussion" : false,
          "hour" : "5",
          "key" : "ecb350d6-6664-4f95-9c1c-2fd1d2f11a40",
          "latitude" : 30.353474,
          "layer" : "",
          "longitude" : -90.98251599999998,
          "meditation" : true,
          "meetingOpen" : false,
          "min" : ":00",
          "name" : "test1",
          "onlyMen" : false,
          "onlyWomen" : false,
          "spanish" : false,
          "speaker" : true,
          "state" : "louisiana",
          "step" : false,
          "street" : "18432 lake iris",
          "timeframe" : "pm",
          "timestamp" : 1457470192281,
          "tradition" : false,
          "type" : "",
          "user" : "facebook:196986260658947",
          "zip" : "70817"
        }
      },
      "states" : {
        "california " : {
          "los angeles" : {
            "25dbab9c-8e4e-45ce-a69b-8641b6579560" : true
          }
        },
        "florida " : {
          "miami" : {
            "3fc846d4-7e55-4134-a0f5-9393aaf02269" : true
          }
        },
        "louisiana " : {
          "alexandria" : {
            "5952bd9f-8438-44b0-addb-a5b806dab5da" : true
          },
          "baton rouge" : {
            "3d2c7948-16e5-466c-b0d8-0a9e24ed7529" : true,
            "ecb350d6-6664-4f95-9c1c-2fd1d2f11a40" : true
          },
          "lafayette" : {
            "7001c8a7-c4f0-44ba-a4fc-2dba32097cc6" : true
          }
        }
      }
    }

    enter image description here

  • Ronnie Royston
    Ronnie Royston over 8 years
    I'm not getting anything in the final values. undefined.
  • Bergi
    Bergi over 8 years
    That means you're returning undefined (or don't return anything) from the then callback where you are creating the promises you're pushing into reads. If you just want to return snap; there, omit the callback completely.
  • Frank van Puffelen
    Frank van Puffelen over 8 years
    @Bergi the snapshot variable is a DataSnapshot object from the Firebase JavaScript SDK. While it implements forEach() it doesn't implement map().
  • Frank van Puffelen
    Frank van Puffelen over 8 years
    Working jsbin of Bergi's code: jsbin.com/hotemaquho/edit?js,console. The only change is that you need to ensure you return something from the inner then().
  • Haves
    Haves almost 7 years
    You also have to change childSnapshot.key(); to childSnapshot.key;
  • Bergi
    Bergi almost 7 years
    @Haves no idea, I just took the OP's code from the question.
  • Mustafa
    Mustafa over 4 years
    I have tried all kinds of solutions for 2 days but I have not been successful. Finally I solved it thanks to your solution! Thanks @Bergi