Dynamically create async function (error) - javascript

I am trying to code asyncfunction but I get an error(await is only valid in async function), the question is: it's possible to do this?
const run_qry = require('./sequelize');
app.post('/resultdata', (req, res) => {
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
let test001 = new AsyncFunction('dat', `{
var mySet = new Set();
var arrObj = [];
// QUERY TO DATABASE
let queryDB = await run_qry.query('select * from public.list_users()');
// LOOP DATA
queryDB.forEach((element, index, array) => {
var row = [];
row.push({vareg: element.val, trans_id: element.id, til_scrip: 1});
row.push({vareg: element.val, trans_id: element.id, til_scrip: 1});
mySet.add(row);
});
// NEW ARRAY
for (let rs of mySet) {
const objReg = new Object();
for (let rs_child of rs) {
objReg["col" + rs_child.vareg] = rs_child.vareg;
objReg["col" + rs_child.vareg + "_type"] = rs_child.til_scrip;
};
arrObj.push(objReg);
};
//RETURNING NEW ARRAY OBJ
return arrObj;
};`);
test001(null).then(x => { res.send(x); });
});
i'm using nodejs and express, i would greatly appreciate any help or any option to do it.
ERROR:
SyntaxError: await is only valid in async function
at new Function (<anonymous>)

The await works only within in the async function. Change your arrow function to arrow async function.
change this line
app.post('/resultdata', (req, res) => {
to this
app.post('/resultdata', async (req, res) => {

Related

Why mongoose is not awaiting for await new MODEL.save()

I have 2 servers and one of these is work fine, but second (modified variant of first) is not
`This is not works:
router.post("/", async (req, res, next) => {
const newBriefAppeal = await new BriefAppeal(req.body);
let appealId;
let target;
let goals;
let brand;
let ***;
try {
const savedBriefAppeal = await newBriefAppeal.save(function (err, appeal) {
appealId = appeal.id;
target = appeal.step01target;
goals = appeal.step02goals;
brand = appeal.step03brand;
*** = appeal.***
});
res.status(200).json(savedBriefAppeal);
} catch (err) {
res.status(500).json(err);
}
});
`
and i got error
node:events:491
throw er; // Unhandled 'error' event
^
TypeError: Cannot read properties of undefined (reading 'id')
`but this variant in my similar project works fine:
router.post("/", async (req, res, next) => {
const newAppeal = await new Appeal(req.body);
let appealId;
let name;
let email;
let phone;
let subject;
let message;
let attachments = [];
try {
const savedAppeal = await newAppeal.save(function (err, appeal) {
appealId = appeal.id;
name = appeal.name;
email = appeal.email;
phone = appeal.phone;
subject = appeal.subject;
message = appeal.text;
attachments = appeal.appealAttach.map((attachment) => ({
filename: attachment,
path: "./uploads/media/mailAttachments/" + attachment,
}));
});
res.status(200).json(savedAppeal);
} catch (err) {
res.status(500).json(err);
}
});
Where's i'm wrong and why my appeal is undefined ?
Because you're passing in a callback. As it says in the documentation, save only returns a promise when you don't pass in a callback:
Returns:
...Returns undefined if used with callback or a Promise otherwise.
Either use the old-style callback signature or use the promise feature.

Storing MongoDB document inside a Node.js array and return it

I try to get specific documents from MongoDB with Node.js and insert them into array.
const getStockComments = async (req) => {
const stockname = req.params.stockName;
var comments = [];
var data = [];
const stock = await stockModel.findOne({ name: stockname });
comments = stock.comments;
comments.forEach(async (commentId) => {
const comm = await commentModel.findOne({ _id: commentId });
data.push(comm);
console.log(data); // This returns the data in loops, because its inside a loop.
});
console.log(data); // This not returns the data and i don't know why.
return data;
};
The first console.log(data) returns the same data a lot of times because its inside a loop.
But the second console.log(data) dosen't returns the data at all.
What I'm doing wrong?
Instead of using loop , you can use $in operator to simplify things .
const getStockComments = async (req) => {
const stockname = req.params.stockName;
var comments = [];
var data = [];
const stock = await stockModel.findOne({ name: stockname });
comments = stock.comments;
commentModel.find({ _id: { $in: comments } }, (err, comments) => {
data = comments;
});
console.log(data);
return data;
};

How to pass object from one file to another in javascript?

I have node js server file (index.js) and client file (orderlist.js)
In index.js i am getting promise object , like that
function returnOrderArray() {
var i = 0;
const promise = new Promise((resolve, reject) => {
connection.query('SELECT * FROM orders', function(error, results) {
while (i < results.length) {
order.id[i] = results[i].id;
order.wavetype[i] = results[i].wavetype;
order.color[i] = results[i].color;
order.thick[i] = results[i].thick;
order.readydate[i] = results[i].readydate;
order.createdate[i] = results[i].createdate;
order.manager[i] = results[i].manager;
i++;
}
resolve(order);
// console.log(order);
});
});
return promise;
}
then i want to pass it to other js file.
I tried to do that with module.exports
app.get('/orderlist', checkUserSession, async function(request, response) {
returnOrderArray().catch(error => console.log(error)).then((() => {
module.exports.order = order;
response.render("orderlist.ejs", { username: request.session.username });
})).catch(error => console.log(error));
});
and then import it in orderlist.js
var ind = require('../../index')
function asd() {
alert(ind.order);
}
but it seems not to work.
What am i doing wrong , and what's the best way to pass objects to other files in js?
oh , and file architecture
filearch
You need to export your module like so: module.exports = returnOrderArray
try this,
orderlist.js
const returnOrderArray = () => {...some code..}
module.exports = returnOrderArray
index.js
const returnOrderArray = require('./path/to/orderlist.js')
const run = async() => {
const orderlist = await returnOrderArray() // use await or then as you prefer
}
run()
async_await link if curious!
Hope this will work :)

Return value to variable from function

I am looking to return a value to a varible when I call the function in nodejs.
The output I am looking for is "Calling From Glasgow to Euston"
The output I am getting is "Calling From undefined to undefined"
Code is the following.
function trainstation(stx, callBack) {
MongoClient.connect(ttdb, function(err, db) {
if (err) throw err;
var dbo = db.db("ttdb");
var collection = dbo.collection("tlc");
var find = collection.find( { "Stanox" : stx } );
find.toArray(function(err, result) {
if (err) throw err;
db.close();
return callBack(result);
});
});
};
function gettrain(){
var ts1 = trainstation(9531, function(x){
return x[0]['Station Name'];
});
var ts2 = trainstation(31033, function(x){
return x[0]['Station Name'];
});
console.log("Calling From", ts1, "to", ts2);
};
gettrain();
Thanks :)
I don't use the MongoDB package and I don't have MongoDB up & running right now to test this, so I've written this code purely based on a quick read of the reference documentation. Perhaps you can test this and we'll fix any minor issues. Copy this code to a new source file and test it.
What I've done is to take advantage of the MongoDB package's promise features. You can see that the code is more linear and simpler to follow.
const MongoClient = require('mongodb').MongoClient;
const ttdb = 'mongodb://localhost:27017'; // or your DB URL
const trainstation = async (Stanox) => {
const client = MongoClient(ttdb);
await client.connect();
const dbo = client.db("ttdb");
const collection = dbo.collection("tlc");
const result = await collection.find({Stanox}).toArray();
client.close();
return result;
};
const gettrain = async () => {
const ts1 = await trainstation(9531);
const ts2 = await trainstation(31033);
const sn1 = ts1[0]['Station Name'];
const sn2 = ts2[0]['Station Name'];
console.log("Calling From", sn1, "to", sn2);
};
gettrain();

NodeJs function inside forEach loop need to complete before go to next item

I have a Nodejs script, where it's detail look like below :
1) it requests to API to get a list of city, it will get JSON array. using this array, I do looping using forEach.
2) at each iteration (2nd loop), I do request again to API to get details (about 100 rows) and insert it into mysql database.
my question, how to make the function inside the first loop (where to get the list of city) wait to complete before going to next item (city). I want to make a loop sequential with delay.
my source code :
const request = require('request');
var moment = require('moment');
var mysql = require('mysql');
var a = moment('2019-04-01');
var b = moment('2019-04-06');
const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));
function timer(ms) {
return new Promise(res => setTimeout(res, ms));
}
var connection = mysql.createConnection({
host : 'localhost',
user : 'user1',
password : 'password',
database : 'local'
});
async function getURL(id_city,dates) {
var url = 'https://localhost/api/format/json/schedule/city/'+id_city+'/date/'+dates;
request(url, { json: true }, (err, res, body) => {
if (err) { return console.log(err); }
// console.log(body.status);
var item1 = body.schedule.data.item1;
var item2 = body.schedule.data.item2;
connection.connect();
connection.query('INSERT INTO schedule (city,item1,item2) values ("'+id_city+'","'+task1+'", "'+task2+'")', function (error, results, fields) {
if (error) throw error;
});
// connection.end();
});
}
async function getDate(id_city)
{
var end;
for (var m = moment(a); m.isBefore(b); m.add(1, 'days')) {
getURL(id_city,m.format('YYYY-MM-DD'));
await timer(1000); //making delay
}
}
async function main () {
var url = 'https://localhost/api/format/json/list_city';
connection.connect();
request(url, { json: true }, (err, res, body) => {
if (err) { return console.log(err); }
var list_city = body.city; //this is an array
var counter = 0;
list_city.forEach(function(city){
getDate(city.id, function(){
});//i need this to complete before go to next city
});
});//end request url
}
main();
my expectation (sequential) :
city1
insert item a done...
insert item b done...
city2
insert item a done...
insert item b done...
insert item c done...
city3
...
For both request and mysql you can use the Promise supported package namely: request-promise and mysql2. To guarantee sequential execution, you can then do:
const rp = require('request-promise');
const mysql = require('mysql2/promise');
// then in your getURL function
async function getURL(id_city,dates) {
var url = 'https://localhost/api/format/json/schedule/city/'+id_city+'/date/'+dates;
const body = await rp(url, { json: true })
const item1 = body.schedule.data.item1;
const item2 = body.schedule.data.item2;
const connection = await mysql.createConnection({host:'localhost', user: 'root', database: 'test'});
const [rows, fields] = await connection.execute('INSERT INTO schedule (city,item1,item2) values ("'+id_city+'","'+task1+'", "'+task2+'")');
}
// One await in getDate should do
async function getDate(id_city) {
var end;
for (var m = moment(a); m.isBefore(b); m.add(1, 'days')) {
await getURL(id_city,m.format('YYYY-MM-DD'));
}
}
For handling error with async/await:
try {
const body = await rp(url, { json: true })
} catch (e) {
// handle erorr
console.error(e);
// or rethrow error: throw e
}
For efficiency you could use mysql connection pool like:
// myPool.js
const mysql = require('mysql2');
// create pool
const pool = mysql.createPool({
host:'localhost',
user: 'root',
database: 'test',
connectionLimit: 10,
queueLimit: 0
});
// now get a Promise wrapped instance of that pool
const promisePool = pool.promise();
module.exports = () => promisePool;
// Then in your getURL
const getPool = require('./myPool');
async function getURL(id_city,dates) {
...
const pool = await getPool();
const [rows, fields] = await pool.execute('INSERT INTO schedule (city,item1,item2) values ("'+id_city+'","'+task1+'", "'+task2+'")');
...
Also consider using prepared statement.
connection.execute('SELECT * FROM `table` WHERE `name` = ? AND `age` > ?', ['Morty', 14]);
Use a for loop instead of forEach, and on each iteration, await the call of getDate, so that one getDate call always finishes before it gets called again:
for (let i = 0; i < list_city.length; i++) {
await getDate(city[i]);
await timer(100); // this will put a delay of at least 100ms between each call
}
Make sure to make the containing function async for this to work.
Note that since getDate returns a Promise, it probably shouldn't accept a callback - either chain awaits or thens on to the end instead.

Categories

Resources