2

I am currently working with Firebase and Firebase functions. I am trying to get documents within a collection (collection : 'items'). I tried doing a GET, however I only get a 200 and empty body.

app.get('/api/read/items', (req, res) => {
(async () => {
    try {
        let response = [];
        let itemRefs = db.collection('items').get().then(snapshot => {
            snapshot.forEach((item) => {
                response.push(item.data());
            });
            console.log(response);
        });
        return res.send(response);
    } catch (error) {
        debug.log(error);
        return res.status(500).send(error);
    }
})();
});

Firebase collection screenshot

Interestingly when I query a specific item, I get the JSON body with the document data included:

app.get('/api/read/:item_id', (req, res) => {
(async () => {
    try {
        const document = db.collection('items').doc(req.params.item_id);
        let item = await document.get();
        let response = item.data();
        return res.status(200).send(response);
    } catch (error) {
        console.log(error);
        return res.status(500).send(error);
    }
})();
});

Looking forward to see what mistake I made :)!

Thank you for your help!

2 Answers 2

2

Data is loaded form Firestore asynchronously. By the time your res.send(response) executes, the snapshot.forEach(...) hasn't been run yet.

The solution is to send the response to the client from within the innermost callback:

app.get('/api/read/items', (req, res) => {
(async () => {
    try {
        let response = [];
        return db.collection('items').get().then(snapshot => {
            snapshot.forEach((item) => {
                response.push(item.data());
            });
            console.log(response);
            return res.send(response);
        });
    } catch (error) {
        debug.log(error);
        return res.status(500).send(error);
    }
})();
});

Alternative, you can use await as you do in your second snippet:

app.get('/api/read/items', (req, res) => {
(async () => {
    try {
        let response = [];
        let snapshot = await snapshot db.collection('items').get();
        snapshot.forEach((item) => {
            response.push(item.data());
        });
        return res.send(response);
    } catch (error) {
        return res.status(500).send(error);
    }
})();
});

Which you can simplify a bit further to:

app.get('/api/read/items', (req, res) => {
(async () => {
    try {
        let snapshot = await snapshot db.collection('items').get();
        let response = snapshot.documents.map((item) => item.data());
        return res.send(response);
    } catch (error) {
        return res.status(500).send(error);
    }
})();
});
Sign up to request clarification or add additional context in comments.

3 Comments

Hi Frank, Thanks for the fast response, I tried the provided code snippet, however I got the same response unfortunately.
Hi Frank, Thank you for the improved code. I think I found the issue, but I am not sure I fully understand the root cause. I will add the code below.
Your answer includes the changes I proposed it seems, so I'm quite sure those contribute to it now working.
0

I think I have found the root cause of the problem, which I can not explain why, due to the lack of knowledge I have with node/express. As I was testing I have my index.js file which contains :

const serviceAccount = require("./permissions.json");
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const express = require('express');
const cors = require('cors');
const app = express();

const db = admin.firestore();
......
app.get('/api/read/items', (req, res) => {
    (async () => {
        try {
            let response = [];
            return db.collection('items').get().then(snapshot => {
                snapshot.forEach((item) => {
                    response.push(item.data());
                });
                console.log(response);
                return res.send(response);
            });
        } catch (error) {
            console.log(error);
            return res.status(500).send(error);
        }
    })();
});

// read item
app.get('/api/read/:item_id', (req, res) => {
    (async () => {
        try {
            const document = db.collection('items').doc(req.params.item_id);
            let item = await document.get();
            let response = item.data();
            return res.status(200).send(response);
        } catch (error) {
            console.log(error);
            return res.status(500).send(error);
        }
    })();
});


app.get('/api/read/geoFencedUsers', (req, res) => {
    (async () => {
        try {
            let response = [];
            return db.collection('geoFencedUsers').get().then(snapshot => {
                snapshot.forEach((geoFencedUser) => {
                    response.push(geoFencedUser.data());
                });
                return res.status(200).send(response);
            })
        } catch (error) {
            return res.status(500).send(error);
        }
    })();
});

Trying to do a GET call on read/geoFencedUsers return 200 but an empty response. After changing my index.js literally moving that get method above, solved the problem making all 3 calls work returning a proper response with data.:

app.get('/api/read/items', (req, res) => {
    (async () => {
        try {
            let response = [];
            return db.collection('items').get().then(snapshot => {
                snapshot.forEach((item) => {
                    response.push(item.data());
                });
                console.log(response);
                return res.send(response);
            });
        } catch (error) {
            console.log(error);
            return res.status(500).send(error);
        }
    })();
});

app.get('/api/read/geoFencedUsers', (req, res) => {
    (async () => {
        try {
            let response = [];
            return db.collection('geoFencedUsers').get().then(snapshot => {
                snapshot.forEach((geoFencedUser) => {
                    response.push(geoFencedUser.data());
                });
                return res.status(200).send(response);
            })
        } catch (error) {
            return res.status(500).send(error);
        }
    })();
});

// read item
app.get('/api/read/:item_id', (req, res) => {
    (async () => {
        try {
            const document = db.collection('items').doc(req.params.item_id);
            let item = await document.get();
            let response = item.data();
            return res.status(200).send(response);
        } catch (error) {
            console.log(error);
            return res.status(500).send(error);
        }
    })();
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.