1

I have 3 async functions:

ToDoItem.deleteMany({}); // deletes entire collection
ToDoItem.insertMany(itemArray); // adds new items to collection
ToDoItem.find({}); // finds all the items in the collection

This code alone doesn't work well, as they do not follow a consistent order. I.e. the insertion might happen before deletion, which I do not want.

I can use callbacks to chain them together (callback hell), and I can also use .then to chain them together, as they return promises. However, I would like to use async/await.

Additionally, these functions can be given optional callbacks, for instance:

ToDoItem.find({}, (data) => { 
  console.log(data); 
});

This is useful as I want to see all the data in my DB that matches the query {} (which is all items).

However I can't figure out how to access these callbacks by using async and await. I can do it via callbacks or .then, but the code is more messy. Is there a way to do this?

Edit:

As per Bergi's reply, I have edited my code as such:

async function setupDatabase() {
  const deleteResult = await ToDoItem.deleteMany({});
  console.log("Items deleted. Delete result:")
  console.log(deleteResult);

  const insertResult = await ToDoItem.insertMany(defaultItems);
  console.log("Items have been added successfully");
  console.log(insertResult);

  const findResult = await ToDoItem.find({});
  console.log("Here are the items:")
  console.log(findResult);
}

Am I correct in thinking that:

  1. deleteResult will now evaluate to be either the deletion confirmation (if successful) or the error (if rejected). And similarly with insertResult and findResult?

  2. What do I do if I want to return the collection found by .find({}), as the function setupDatabase is now async and returns a promise.

  3. If 1) is correct, how do I separate out when I'm getting an error and when I'm getting a result?

As per Konrad's response, I have done the following:

async function setupDatabase() {
  const deleteResult = await ToDoItem.deleteMany({});
  console.log("Items deleted. Delete result:")
  console.log(deleteResult);

  const insertResult = await ToDoItem.insertMany(defaultItems);
  console.log("Items have been added successfully");
  console.log(insertResult);

  const findResult = await ToDoItem.find({});
  console.log("Here are the items:")
  console.log(findResult);

  return findResult;
}


app.get("/", function(req, res) {
  (async function() {
    const objectList = await setupDatabase();
    let dataList = [];
    
    for (element of objectList) {
      dataList.push(element.todo);
    }
    res.render("list", {listTitle: "Today", newListItems: dataList});
  }());

My idea was to return the findResult inside the setupDatabase function. But this is actually a promise since the function is async, so I wrapped it in an IIFE inside the .get. I then iterated over this list and created dataList which has the actual data I want to render.

713sean
  • 313
  • 11
  • *deleteResult will now evaluate to be either the deletion confirmation (if successful) or the error (if rejected)* - no, errors will be thrown, if you want to handle them, you have to catch them – Konrad Nov 17 '22 at 22:10
  • *What do I do if I want to return the collection found by .find({})* - you use `return` statement and in the called you can handle the promise as usuall – Konrad Nov 17 '22 at 22:10
  • Konrad, thank you for your responses. I have to sit on the first one for a bit. The second one I made an edit in my post if you are able to take a look. I think I got it (the code works) I just wanted to verify if you had any notes or concerns. Thank you. – 713sean Nov 17 '22 at 22:28
  • FYI, on StackOverflow you should NOT edit your question to show the solution. Answers belong in answers, not in questions. If the provided answers don't show the answer you want, you can post your own answer. – jfriend00 Nov 18 '22 at 00:33
  • Thanks jfriend00, I couldn't figure out that functionality as I was new, but I see it now. – 713sean Nov 18 '22 at 01:19

1 Answers1

2

You don't use async/await with callbacks.

You use await with promises, and you should not mix those with callbacks - in particular, MongoDB does not return a promise when you pass a callback. You need to write

await ToDoItem.deleteMany({}); // deletes entire collection
await ToDoItem.insertMany(itemArray); // adds new items to collection
const data = await ToDoItem.find({});

Am I correct in thinking that [the await expression] will now evaluate to be either the deletion confirmation (if successful) or the error (if rejected)?

No. The result of the await is the successful promise fulfillment value. In case of a promise rejection, the error is thrown as an exception, you can handle it with a try/catch block.

What do I do if I want to return the collection found by .find({}), as the function setupDatabase is now async and returns a promise.

The async/await syntax doesn't change anything. The function was asynchronous before, and it's impossible to immediately return the result, regardless whether you'd use callbacks or promise .then() chaining syntax or await syntax. Returning a promise is actually desirable - the caller just has to wait for it!

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thank you, that makes sense. I have created an edit in my post to reflect my updated code. I also wrote two follow-up questions in there as well if you are able to check them out. Thanks for your time in writing this reply and answer! – 713sean Nov 17 '22 at 22:04