timthedev07
timthedev07

Reputation: 454

Firestore slow queries are causing the entire logic to crash

I am currently designing a todo app with react and firebase without any node js server code. Everything was fine when inserting data and authenticating, but when I tried to query all the tasks where uid equals a certain value(that means all the tasks that belongs to a particular user), somehow the query gets skipped and returns null. But then, after a second or so, the array got retrieved and printed out.

The code:

function retrieveTasksOfUser(uid) {
    // get all tasks where the uid equals the given value
    return db.collection("tasks").where("uid", "==", uid).get();
}

function retrieveTasks() {
    let res = [];
    retrieveTasksOfUser(currentUser["uid"])
    .then((snapshot) => {
        snapshot.forEach((doc) => {
        // include the doc id in each returned object
            let buffer = doc.data();
            buffer["id"] = doc.id;
            res.push(buffer);
        });
        console.log(res);
        return res;
    })
    .catch((err) => {
        console.error("Error retrieving tasks: ", err);
        return res;
    });
}
let tasks = retrieveTasks();
console.log({ tasks });

EDIT: Inspired by Frank's answer, I modified my code and got:

    async function retrieveTasks() {
        let res = [];
        const snapshot = await retrieveTasksOfUser(currentUser["uid"]);
        snapshot.forEach((doc) => {
            let buffer = doc.data();
            buffer["id"] = doc.id;
            res.push(buffer);
        });
        return res;
    }

    let tasks = [];
    let promise = retrieveTasks();
    promise.then((res) => {
        console.log("Tasks are");
        tasks = res;
        console.log(res);
    });
    console.log(tasks);

But the result turns out to be an empty array

Thanks a bunch in advance.

Upvotes: 0

Views: 45

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598847

You're not returning anything from the top-level code in retrieveTasks, so that means that tasks will always be undefined.

The simplest fix is to return the result of the query, which then means that your return res will be bubbled up:

return retrieveTasksOfUser(currentUser["uid"])
    ...

But this means you're returning a promise, as the data is loaded asynchronously. So in the calling code, you have to wait for that promise to resolve with then:

retrieveTasks().then((tasks) => {
    console.log({ tasks });
})

You can make all of this a lot more readable (although it'll function exactly the same) by using the async and await keywords.

With those, the code would become:

async function retrieveTasks() {
    let res = [];
    const snapshot = await retrieveTasksOfUser(currentUser["uid"]);
    snapshot.forEach((doc) => {
        let buffer = doc.data();
        buffer["id"] = doc.id;
        res.push(buffer);
    });
    return res;
}
let tasks = await retrieveTasks();
console.log({ tasks });

Or with a bit more modern JavaScript magic, we can make it even shorter:

async function retrieveTasks() {
    const snapshot = await retrieveTasksOfUser(currentUser["uid"]);
    return snapshot.docs.map((doc) => { ...doc.data, id: doc.id });
}
let tasks = await retrieveTasks();
console.log({ tasks });

Upvotes: 1

Related Questions