Issue
My goal is to create an abstracted POST function for an express running on Node similar to Django’s inbuilt REST methods. As a part of my abstracted POST function I’m checking the database (mongo) for valid foreign keys, duplicates, etc…, which is where we are in the process here. The function below is the one that actually makes the first calls to mongo to check that the incoming foreign keys actually exist in the tables/collections that they should exist in.
In short, the inbuilt response functionality inside the native .map
function seems to be causing an early return
from the called/subsidiary functions, and yet still continuing on inside the called/subsidiary functions after the early return
happens.
Here is the code:
const db = require(`../../models`)
const findInDB_by_id = async params => {
console.log(`querying db`)
const records = await Promise.all(Object.keys(params).map(function(table){
return db[table].find({
_id: {
$in: params[table]._ids
}
})
}))
console.log('done querying the db')
// do stuff with records
return records
}
// call await findIndDB_by_id and do other stuff
// eventually return the response object
And here are the server logs
querying db
POST <route> <status code> 49.810 ms – 9 //<- and this is the appropriate response
done querying the db
… other stuff
When I the function is modified so that the map function doesn’t return anything, (a) it doesn’t query the database, and (b) doesn’t return the express response object early. So by modifying this:
const records = await Promise.all(Object.keys(params).map(function(table){
return db[table].find({ // going to delete the `return` command here
_id: {
$in: params[table]._ids
}
})
}))
to this
const records = await Promise.all(Object.keys(params).map(function(table){
db[table].find({ // not returning this out of map
_id: {
$in: params[table]._ids
}
})
}))
the server logs change to:
querying db
done querying the db
… other stuff
POST <route> <status code> 49.810 ms – 9 // <-appropriate reponse
But then I’m not actually building my query, so the query response is empty. I’m experiencing this behavior with the anonymous map function being an arrow function of this format .map(table => (...))
as well.
Any ideas what’s going on, why, or suggestions?
Solution
Your first version of your code is working as expected and the logs are as expected.
All async
function return a promise. So findInDB_by_id()
will always return a promise. In fact, they return a promise as soon as the first await
inside the function is encountered as the calling code continues to run. The calling code itself needs to use await
or .then()
to get the resolved value from that promise.
Then, some time later, when you do a return someValue
in that function, then someValue
becomes the resolved value of that promise and that promise will resolve, allowing the calling code to be notified via await
or .then()
that the final result is now ready.
await
only suspends execution of the async
function that it is in. It does not cause the caller to be blocked at all. The caller still has to to deal with a promise returned from the async
function.
The second version of your code just runs the db queries open loop with no control and no ability to collect results or process errors. This is often referred to as "fire and forget". The rest of your code continues to execute without regard for anything happening in those db queries. It’s highly unlikely that the second version of code is correct. While there are a very few situations where "fire and forget" is appropriate, I will always want to at least log errors in such a situation, but since it appears you want results, this cannot be correct