Lion Smith
Lion Smith

Reputation: 655

how to join two tables and get all data base on child in firebase

i wanted to get the data from two tables in firebase db the 1st table was

enter image description here

from here i want to get the next data from table based on the hospital_fk

enter image description here

this is the result it got on my json

enter image description here

and here is my script for getting the data..

router.get('', function(req, res){
    var booths = database.ref('booths');
    var hospital = database.ref('hospitals');

        booths.once('value', function (snapshot) {
            var dataSet = [];
            snapshot.forEach(function (childSnapshot) {
                    
                var childKey = childSnapshot.key;
                var fk = snapshot.child(childKey).val();
                
                hospital.child(childSnapshot.val().hospital_fk).on('value', hospital=>{
                var childData =  _.assign(fk, hospital.val());
                
                    dataSet.push({
                        childKey: childKey, 
                        childData: childData
                    });

                    res.json(dataSet);
                });
            });

            
        });
});

now my problem was only the first data is being returned and also getting an error.. says that FIREBASE WARNING: Exception was thrown by user callback. Error: Can't set headers after they are sent.

any idea on how to get all the records and what's the best approach on joining two tables.

Upvotes: 0

Views: 2694

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598886

When you call res.json(dataSet) it sets a header that your response is JSON, and sends the JSON. You can only set headers on the response before sending data, so the second time you make this call, Node.js will rightfully throw an error saying that it can't set the header.

What you'll need to do is first gather all joined data into a single JSON response, and then send it in one go after you've loaded all of them. To do this you use a list of promises and Promise.all():

router.get('', function(req, res){
    var booths = database.ref('booths');
    var hospital = database.ref('hospitals');

    booths.once('value', function (snapshot) {
        var promises = [];
        snapshot.forEach(function (childSnapshot) {

            var childKey = childSnapshot.key;
            var fk = snapshot.child(childKey).val();

            var promise = hospital.child(childSnapshot.val().hospital_fk).once('value');

            promises.push(promise);
        });
        Promise.all(promises).then(function(snapshots) {
            var dataSet = [];
            snapshots.forEach(function(hospital) {

                var childData =  _.assign(hospital.key, hospital.val());

                dataSet.push({
                    childKey: hospital.key, 
                    childData: childData
                });

            });
            res.json(dataSet);
        });

    });
});

Now the code only calls res.json(dataSet) once, after it's gotten all of the hospital data.

You'll note that I also changed your on('value' to once('value', since I doubt you'll want to keep the listener active for more than just one read.

Upvotes: 1

Related Questions