async/await and templating with pug - javascript

I'm new to using async/await in nodejs and am confused about how to return data that I want for use in a view. Here is my code. below is the homeController, which is used like so:
app.get("/", homeController.index);
I tried making the index method async, but i still can't console out the news data. what is the right way to resolve the article information so it's available for consumption in the view in home?
async function getNewsData() {
const pool = await connection;
const result = await pool.request()
.input("StoryID", sql.Int, 154147)
.execute("News.uspStoryByIdGet");
console.log(result, "the result from the stored procedure");
return result;
}
const article = getNewsData().
catch((e) => {
console.log("the error", e);
});
export let index = async(req: Request, res: Response) => {
const article = await getNewsData();
console.log(article, "yoo");
res.render("home", {
article,
title: "Home",
});
};

for what I can see you should probably not be awaiting for connection in your getNewsData unless for some reason connection is a promise that is was or is waiting to be resolved.
you should also be returning result on getNewsData function.
If that is not what is causing the problems there here are some clarifications about async/await
1 - Calling an async function behaves similar to calling a function that returns a Promise
2 - when you use await its behaves as if you wait for a promise to be resolved and extract the result from it, which you would have in your scope instead of having passed to a callback function in the then or catch methods.
feel free to reply to this answer if still in doubt.

No value is returned fromgetNewsData() function call, see Why is value undefined at .then() chained to Promise? You can return row from getNewsData() if expected result of getNewsData() call is rows array.

Related

How to return an 'await' variable in JavaScript?

I have the following JS code
async function readAtlasAll() {
return await MongoClient.connect(url, async function(err, db) {
var dbo = db.db("Users");
c = dbo.collection("List");
r = await c.find({}).toArray();
console.log(r);
return r;
});
}
console.log(readAtlasAll());
I'm not sure why, but printing the result of readAtlasAll() comes before printing the variable r inside the function, even though I'm awaiting the result of r beforehand. The terminal prints Promise { <pending> } first and afterwards prints the contents of r.
I'm relatively new to JavaScript, so I would really appreciate the help. Thanks!
You cannot use both await and a plain callback on MongoDB API calls as the await won't do anything useful. Use one or the other, not both. This is because the MongoDB asynchronous APIs will return a promise if you do NOT pass a callback to them and you can then await that promise, but if you pass a callback, they do not return a promise, therefore the await does nothing useful at all. Here's how you would implement it by leaving out the callback and using await:
async function readAtlasAll() {
const db = await MongoClient.connect(url);
const dbo = db.db("Users");
const c = dbo.collection("List");
const r = await c.find({}).toArray();
return r; // this will be the resolved value of the returned promise
}
readAtlasAll().then(r => {
console.log(r);
}).catch(err => {
console.log(err);
});
Keep in mind that await has no magic powers at all. ALL it does is suspend execution of the function until a promise resolves/rejects. So, it only does anything useful when you await a promise.
And, further, ALL async functions return a promise so there is NO way to return an asynchronously-retrieved value directly from your function. You have to use an asynchronous mechanism for communicating back an asynchronously retrieved value such as a promise, a callback or an event. So readAtlasAll() can never return your value directly.
See How to return the response from an asynchronous call for more info on that.

How to get neo4j query result returned from .then with node js

I would need to get the data returned by using the Neo4j driver for Node JS. My problem is, that i can print the value of 'online' out on console inside the .then call but i can't seem to get access to it outside of that part - I have tried returning record.get('onl'), assign it to a pre-defined variable outside the function but nothing works - all i get as result if i try to, for example, print the value of online out at the last line in this snippet, is Promise { <pending> }. I suppose I don't do the promise handling right, and I looked up lots of tutorials and examples, but I can't work it out. So: how could i assign the returned data (record.get('onl')) to var online and get actual result instead of the promise?
Thanks in advance :)
var online = session.run(cyp1, param).then(results => {
return results.records.map(record =>{
console.log(record.get('onl'))
return record.get('onl')
})
}).then(()=>{
session.close()
});
console.log(online)
Currently, you are assigning var online as a 'Promise Chain' & not a 'Resolved Promise'. You could use Async/Await this will allow you to write async code in a synchronous manner.
async function getRecords(){
const records = await session.run(cyp1, param);
return records.map(record => record.get('onl'))
}
const online = await getRecords();
Use try/catch/finally
try {
const online = await getRecords();
} catch (error) {
// do something
} finally {
await session.close()
}
If you wanted to continue using .then()
You need to use 'Promise Chaining' and pass the value 'Down the chain', this results in complex 'Callback'/'Promise Chain' hell.
session.run(cyp1, param).then(results => {
return results.records.map(record => record.get('onl'))
}).then((online)=> {
console.log(online)
}).catch(() => {
// do something
}).finally(() => {
session.close()
});

Async Mysql Query in Node.js

I want to get a specific value from my mysql database and then pass it to an API. So I have to wait for the query to finish. I found this async/await example on stackoverflow. But it's not working for me.
async function getUTC() {
try {
let result = await db.query(`SELECT utcEndSeconds FROM mp_games ORDER BY utcEndSeconds ASC LIMIT 1`)
return result
} catch (err) {
console.log(err)
}
}
let newUTC = getUTC()
console.log(newUTC)
newUTC.then(data => {
console.log(data)
})
The first console.log(newUTC) prints Promise { pending }. I expected to find my data here, because await should already resolve the promise???
Then I added the .then() block. console.log(data) prints a big object (mysql I guess) but my data is nowhere to be found in the object.
What am I missing here? Thanks in advance.
You have problems with understanding of async/await pattern.
newUTC.then(data => {
console.log(data)
})
the above code resolves promise and return you data object. but console.log(newUTC) gives you promise pending because it is not awaited nor encapsulated with promise for resolution.
if you change
let newUTC = getUTC()
console.log(newUTC)
to
let newUTC = getUTC()
console.log(await newUTC)
then first the code awaited and the result is passed to the console.log.
EDIT: await only works within async function. IF your function is not async then you need to use promise approach.
let newUTC = getUTC()
newUTC.then(data => console.log(data));
I think it's easier to use mysql.query callback function and run the rest of my code inside. It's not as pretty but works
db.query(`SELECT utcEndSeconds FROM mp_games ORDER BY utcEndSeconds ASC LIMIT 1`, (err, result) => {
let newUTC = result[0].utcEndSeconds
... rest of my code (api calls etc...)
}

Next block of code execute earlier before the fetch how can I fixed that

It should have given me not null output but I am getting null output. It is working fine if I console inside the block of code but outside it gives me null value
Here is the code:
app.post("/downloadDb",async (req,res)=>{
var docData = [];
var idList = [];
console.log("downloadBd");
const mahafuzCol = firestore.collection("Mahafuz")
await mahafuzCol.listDocuments()
.then( listDoc=>{
//List of id fetch
listDoc.forEach(data=>{
idList.push(data.id)
});
}).catch(e=>console.log(e));
//document is fetched
await idList.forEach(id=>{
mahafuzCol.doc(id).get().then(
doc=>{
docData.push(doc.data());
//Here I get desire output w=if I log with console
}
);
});
//Here I get null output
await console.log(docData);
});
Ok, looking at your piece of code, I would like to point out a few things.
You are using the latest and greatest ES7 async and await feature which is great. Why are you stuck with the old way of defining variables? Try to use let and const instead of var. Don't mix the ECMAScript versions like this. This is considered a bad practice.
Loops in Node.js are synchronous as of now (though asynchronous loops are in the pipeline of Node and we would see them soon). You cannot put asynchronous code inside a loop and expect them to work as expected. There is a whole concept of event loop in Node.js and how Node handles asynchronous tasks. So, if you have time, you should definitely go through the event loop concepts.
Here is the better way to write the code:
app.post('/downloadDb', async (req, res) => {
// always wrap asynchronous code in async/await in try/catch blocks
console.log('downloadBd');
const mahafuzCol = firestore.collection('Mahafuz');
try {
// assuming that listDocuments returns a promise
// await on it until it gets resolved
// all the listed documents will be assigned to docs
// once the promise is resolved
const docs = await mahafuzCol.listDocuments();
const idList = docs.map(data => data.id);
// again assuming that get() returns a promise
// pushing all the promises to an array so that
// we can use Promise.all to resolve all the promises
// at once
const promisesList = idList.map(id => mahafuzCol.doc(id).get());
// fetching document is here
// once all the promises are resolved, data contains
// the result of all the promises as an array
const data = await Promise.all(promisesList);
const docData = data.map(doc => doc.data());
console.log(docData);
// return some response
return res.status(200).send();
} catch (error) {
console.log('error: ', error);
// return some response
return res.status(500).send();
}
});
PS:
If you still somehow want to use asynchronous loops, have a look at this library
https://caolan.github.io/async/docs.html#each
Since forEach is async in nature, as soon as you write a promise in a forEach() loop. The next command gets executed, which in your case is:
// Here I get null output
await console.log(docData);
You'd need the typical for loop for this task:
Try the snippet below:
let idListLen = idList.length;
for (let i =0; i< idListLen; i++) {
mahafuzCol.doc(id).get().then(
doc=>{
docData.push(doc.data());
//Here I get desire output w=if I log with console
}
);
}
console.log(docData) //prints the list of data

WHy am I getting a SyntaxError: Unexpected identifier in forEach with await?

I have an object with a series of named SQL query templates that I'm trying to execute.
The query() method is async, so I should be able to run it with await, but I get an Unexpected identifier error. If I take off the await, then I don't get an error, but I'm stuck with a Promise object...
Object.entries(sqlquerries).forEach(([queryName, queryTpl]) => {
try {
const querystr = replVars(queryTpl, vars);
report[queryName] = await query(querystr);
} catch (err) {
console.error('An error occured running the query : ', err );
}
});
return report;
Why would that be? What can I do to construct my report object and get around this error?
Any help/pointers would be greatly appreciated.
Because the function await appears in (the forEach callback) isn't an async function. If you make it one, beware that forEach does nothing with the callback's return value, which will be a promise if it's an async function, and so you need to be sure to handle errors inline (which you're doing).
But, your return report suggests you're expecting to wait for this process to complete. Beware that forEach will not wait for the previous iteration's promise to resolve before proceeding with the next. If you want to do that, use the promise reduce trick instead and await the result (I assume this is all in an async function):
await Object.entries(sqlqueries).reduce((p, [queryName, queryTpl]) => {
const querystr = replVars(queryTpl, vars);
return p.then(async() => {
report[queryName] = await query(querystr);
});
}, Promise.resolve());
return report;
Or if you can run the queries in parallel, use map and Promise.all instead, and again await the result:
await Promise.all(Object.entries(sqlqueries).map(async ([queryName, queryTpl]) => {
const querystr = replVars(queryTpl, vars);
report[queryName] = await query(querystr);
}));
return report;

Categories