Node JS mysql looping query push to array - javascript

I'm having some trouble with below code. Can someone please take a look and advise what's going on?
const name = ["a", "b", "c"]
let query1 = ('SELECT name FROM table WHERE name = ? AND status IN ("Pending","Active") limit 1')
if (name instanceof Array) {
async function getNames() {
try {
name.forEach(async (name) => {
let newName = []
let rows = await promisePool.query(query1, name);
if (rows[0].length > 0) {
if (rows[0])
newName.push(rows[0][0].uid_name)
console.log(newName)
}
return (rows);
})
}
catch (err) {
console.log('ERROR => ' + err);
return err;
}
}
await getNames();
console.log(newName) returns (if row is found)
['a']
['b']
how can I push any returning value to the array ? desired output ['a','b'] so I can compare it to the original array.
Thanks in advance,
Ucin
I have changed the code a bit but to be honest I'm still not that of an expert.
const name = ["a","b","c"]
let query1 = ('SELECT name FROM table WHERE name = ? AND status IN ("Pending","Active") limit 1')
if (name instanceof Array) {
async function getNames() {
try {
for(names of name) {
let rows = await promisePool.query(query1,[uid,challenge_type,names]);
return (rows);
}
}
catch (err) {
console.log('ERROR => ' + err);
return err;
}
}
let newVar = await getNames();
console.log(newVar[0])
the newVar only returns 1 line, where there should be 2 names.
name.forEach(async (element) => {
let rows = await promisePool.query(query1,[uid,challenge_type,element]);
if (rows[0].length > 0) {
if (rows[0])
/* newName.push(rows[0][0].uid_name) */
console.log(rows[0])
return (rows);
if I go with forEach...Of, I can console.log it within scope, but return(rows) is undefined

Is there a specific reason you are looping through the names and executing a query per name? If all you want to do is see which of those names in the array already exist in your database you could do it all in a single query. Something like:
const names = ["a","b","c"];
const query = 'SELECT name FROM table WHERE name IN (?) AND status IN ("Pending","Active")';
const result = await promisePool.query(query, [names]);
console.log(result);

Related

How to use for loop in mongoose find function?

Here is my code:
app.post('/update', async (req, res, done) => {
let drive = req.app.get('drive');
let fileId = req.body.id;
let subject = req.body.subject;
let grade = req.body.grade;
let industry = req.body.industry;
await TagFile.findOne({id: fileId}, (err, res) => {
if (err) return console.log(err);
//console.log(res);
//console.log(subject);
takeRes(res);
})
function takeRes(res) {
for (let i = 0; i > subject.length; i++) {
if(!res[0].subject.includes(subject[i])) {
res[0].subject.push(subject[i]);
console.log(res[0].subject)
console.log("first was called")
}
else {
console.log(res[0].subject)
console.log("else was called.")
}
}
}
})
This is a post request that is made from my site. When it gets to the step where the for loop needs to be used, I don't get anything in the console from the if else statements. I know this probably has something to do with async, but I don't fully understand it, and would love a push in the right direction. Thank you!
When you are using await you don't need to use the callback function. Use following snippet to query with mongoose, rest of the parts depends on your business logic:
const res = await TagFile.findOne({id: fileId}).exec();
takeRes(res)
result of findOne() is object and result of find() is array and when you use findOne() the res[0] is incorrect and you can use lean()to convert model to object, so use find like this:
let res = await TagFile.find({ id: fileId }).lean();
for (let i = 0; i > subject.length; i++) {
if (!res[0].subject.includes(subject[i])) {
res[0].subject.push(subject[i]);
console.log(res[0].subject);
console.log("first was called");
} else {
console.log(res[0].subject);
console.log("else was called.");
}
}
when you use findOne try like this:
let res = await TagFile.findOne({ id: fileId });
for (let i = 0; i > subject.length; i++) {
if (!res.subject.includes(subject[i])) {
res.subject.push(subject[i]);
console.log(resizeTo.subject);
console.log("first was called");
} else {
console.log(res.subject);
console.log("else was called.");
}
}

Cannot await for sqlite3.Database.get() function completion in Node.js

I'm struggling with some basic async/await problem in node.js using node-sqlite3.
My objective is to select some value from SQLite DB, check it for some condition and take some actions in case the condition is met. Here's the code:
const sqlite3 = require('sqlite3').verbose();
main();
async function main() {
let ordersDb = await createDbConnection('./ProcessedOrders.db');
var orderProcessed = await orderAlreadyProcessed(ordersDb, "555");
console.log("orderProcessed = " + orderProcessed);
if (!orderProcessed) {
console.log("So condition is met!");
}
}
async function orderAlreadyProcessed(ordersDb, orderNumberStr) {
console.log('starting orderAlreadyProcessed function'); //DEBUG
var result;
var query = 'select count(SoldOrderNumber) as "recsCount" from ProcessedSoldOrders where SoldOrderNumber = ?;';
await ordersDb.get(query
,[orderNumberStr]
,(err, row) => {
console.log('Row with count = ' + row); //DEBUG
console.log('row.recsCount = ' + row.recsCount); //DEBUG
result = typeof row !== 'undefined' && row.recsCount > 0;
});
console.log('Returning ' + result); //DEBUG
return result;
}
async function createDbConnection(dbFileName) {
let db = new sqlite3.Database(dbFileName, (err) => {
if (err) {
console.log(err.message);
}
});
return db;
}
But what I get is code executing further, not awaiting for Database.get() method at all! As a result, here's what I see printing in console:
starting orderAlreadyProcessed function
Returning undefined
orderProcessed = undefined
So IF condition met!
Row with count = [object Object]
row.recsCount = 1
As we can see, we return from orderAlreadyProcessed too early with return value = 'undefined'. So condition is met, actions taken, and only then Database.get() returns. But if it was properly awaited, condition would not be met.
How can I make it await for result value?
Since you want to use async/await, and the node-sqlite3 (sqlite3) library does not support the Promise API, you need to use the node-sqlite (sqlite) library, which is a wrapper over sqlite3 and adds support for the Promise API. Then, your code will look something like this:
const sqlite3 = require('sqlite3');
const { open } = require('sqlite');
async function main() {
try {
sqlite3.verbose();
const ordersDb = await createDbConnection('./ProcessedOrders.db');
const orderProcessed = await orderAlreadyProcessed(ordersDb, "555");
console.log("orderProcessed = " + orderProcessed);
if (!orderProcessed) {
console.log("So condition is met!");
}
} catch (error) {
console.error(error);
}
}
async function orderAlreadyProcessed(ordersDb, orderNumberStr) {
try {
console.log('Starting orderAlreadyProcessed function');
const query = 'SELECT COUNT(SoldOrderNumber) as `recsCount` from ProcessedSoldOrders where SoldOrderNumber = ?;'
const row = await ordersDb.get(query, [orderNumberStr]);
console.log('Row with count =', row);
console.log('row.recsCount =', row.recsCount);
const result = typeof row !== 'undefined' && row.recsCount > 0;
console.log('Returning ' + result);
return result;
} catch (error) {
console.error(error);
throw error;
}
}
function createDbConnection(filename) {
return open({
filename,
driver: sqlite3.Database
});
}
main();
I specifically did not remove your console.log and other parts of the code so as not to confuse the original logic of your program.
If we don't to use another library
then we can return a new Promise function & use await, as below:
Note: Below has example for INSERT/run, instead of SELECT/get, but promise/await works same
const sqlite3 = require("sqlite3").verbose();
let db;
db = new sqlite3.Database('./Chinook.db');
function insert() {
return new Promise((resolve, reject) => { // return new Promise here <---
const userId = uuid4();
let sql = `INSERT INTO Users(id) VALUES (?)`; // INSERT <----
let params = [userId];
return db.run(sql, params, function (err, res) { // .run <----
if (err) {
console.error("DB Error: Insert failed: ", err.message);
return reject(err.message);
}
return resolve("done");
});
});
}
let result = await insert(); // now await works fine <------
res.send({ result });

Dialogflow : Getting in an array all document IDs of a firestore collection (javascript node)

I have been trying to retrieve all documents IDs from my firestore collection.
Eg. if there are two documents in my collection, i would like to get an array with all the document IDs in the collection.
ie: var myArray = ['HhYaTvok4qJaIAVI9R0','2AO4RbZ6K5Db4q3OSqi'];
I have been trying to use some pieces of code from the firestore documentation (https://github.com/firebase/snippets-node/blob/9ae3a00985b53025fdc82716046882af71b6009d/firestore/main/index.js#L622-L627).
But it does not retrieve anything in the conversation flow
Below my code in index.js (inline editor).
// The function to get documents ids
const arraymaker = (db) => {
let platformRef = db.collection('quiz');
let all_doc = platformRef.get();
return all_doc
.then(snapshot => {
var myArray =[];
snapshot.forEach(doc => {
myArray.push(doc.id);
});
})
.catch(err => {
console.log('Error getting documents', err);
});
};
// database retrieve
app.intent('Read Random Quizz', (conv) => {
// Trying to get Data from firestone DB,
//var myArray = ['HhYaTvok4qJaIAVI9dR0','2AO4RbZ6K5Db4q3OS7qi'];
var myArray = arraymaker(db);
var rand = myArray[Math.floor(Math.random() * myArray.length)];
var platformRef = db.collection("quiz").doc(rand);
return platformRef.get()
.then( snap => {
var dat = "";
var answ = "";
if (snap.exists) {
dat = snap.data().question;
answ = snap.data().answer;
}
// This is the response for Actions on Google
reply(conv,`The question is ${dat} and the answer is ${answ}`);
})
.catch( err => {
console.log("error...", err);
});
});
I think the problem comes from :
var myArray = arraymaker(db);
It just does not return myArray with all the doc ids.
When i run just the function separatly, i can see an firestore appending all the id in an array.But just in the firestore log. It does not return the final myArray not in the conversation flow.
You have to return all_doc in sec example. app.intent have to return a promise like first example, and you are not returning anything inside it in second example.
Besides you are overriding myArray with console.log !! and calling reply with each doc, I am not familiar with firestore but I think you have to call reply after for each and change overriding myArray
var myArray ="";
snapshot.forEach(doc => {
myArray += doc.id;
});
reply(conv,`Your list of IDs is ${myArray}`);
I did this, and this seems to work. Initially, what i wanted was to retrieve a random document, so i am pasting the solution i found. As mentionned, i am a noob in javascript, and this is probably a very bad code. So any suggestions on how to improve this would be higly welcomed.
var GlobalVariable;
// The function to get documents ids in an array called GlobalVariable
const arraymaker = () => {
let platformRef = db.collection('quiz');
let all_doc = platformRef.get();
return all_doc
.then(snapshot => {
var myArray =[];
snapshot.forEach(doc => {
myArray.push(doc.id);
GlobalVariable= myArray;
});
})
.catch(err => {
console.log('Error getting documents', err);
});
};
// database retrieve
app.intent('Read Random Quizz', (conv) => {
arraymaker(); // restart function to get all the IDs in an array
// take a random ID and read the document
var rand = GlobalVariable[Math.floor(Math.random() * GlobalVariable.length)];
var platformRef = db.collection("quiz").doc(rand);
return platformRef.get()
.then( snap => {
var dat = "";
var answ = "";
if (snap.exists) {
dat = snap.data().question;
answ = snap.data().answer;
}
// This is the response for Actions on Google
reply(conv,`The question is ${dat} and the answer is ${answ}`);
})
.catch( err => {
console.log("error...", err);
});
});

How to use chaining promise together with for loops of arrays?

So, I have this code. I'm trying to debug it in forever. I dont know why it is returning error. I might have some element of promise I forgot or I have something wrong with my array.push 'cause when I look at the log, it throws error on line where I push some objects into array.
Here is my code so far:
router.post('/inventory/product/stocks/add/(:id)', authenticationMiddleware(), function(req, res, next) {
const db = require('../db.js')
var product_no = req.params.id
var cog = req.body.cog
var size_slug = req.body.size_slug
var size_name = req.body.size_name
var rowinserted = 0
var initial_stock = req.body.initial_stock
var stock_id = new Array
var batch_id = new Array
var stock = new Array
var batch = new Array
new Promise(function(resolve, reject) {
console.log('one');
// Getting product product_slug for product_sku
let sql = `SELECT product_slug
FROM inventory_tbl
WHERE product_no = ?`
db.query(sql, [req.params.id], (error, results, fields) => {
if (error) {
throw error;
} else {
var product_slug = results[0].product_slug
resolve(product_slug)
}
})
})
.then(function(value) {
console.log('two');
// Insert product sizes together with its initial stock
for (var x = 0; x < size_slug.length; x++) {
var product_sku = value + size_slug[x]
var slug = size_slug[x]
var name = size_name[x]
var initial_stock = initial_stock[x]
console.log(product_sku);
if (size_slug[x] != '') {
stock.push({
product_sku: product_sku,
product_no: product_no,
size_slug: slug,
size_name: name,
total_stock: initial_stock,
available_stock: initial_stock
})
}
console.log(stock);
}
for (var x = 0; x < size_slug.length; x++) {
var product_sku = value + size_slug[x]
var initial_stock = initial_stock[x]
if (size_slug[x] != '') {
batch.push({
product_no: product_no,
product_sku: product_sku,
production_date: mysql.raw('CURRENT_TIMESTAMP'),
batch_cog: cog,
initial_stock: initial_stock,
stock_left: initial_stock
})
}
console.log(batch);
}
return value
})
.then(function(value) {
console.log('three');
// Insert rows to product_tbl and stock_tbl
for (var i = 0; i < stock.length; i++) {
let sql = `INSERT INTO product_tbl(product_sku, product_no, size_slug, size_name, total_stock, available_stock) VALUES (?, ?, ?, ?, ?, ?)`
db.query(sql, [stock[i].product_sku, req.params.id, stock[i].size_slug, stock[i].size_name, stock[i].total_stock, stock[i].available_stock], (error, results, fields) => {
if (error) throw error
db.query(`SELECT LAST_INSERT_ID() AS id;`, (error, results, fields) => {
stock_id[i] = results[0].id
})
})
sql = `INSERT INTO stocks_tbl(product_no, product_sku, production_date, batch_cog, initial_stock, stock_left) VALUES (?, ?, CURRENT_DATE, ?, ?, ?)`
db.query(sql, [req.params.id, batch[i].product_sku, batch[i].batch_cog, batch[i].initial_stock, batch[i].stock_left], (error, results, fields) => {
if (error) throw error
db.query(`SELECT LAST_INSERT_ID() AS id;`, (error, results, fields) => {
batch_id[i] = results[0].id
})
})
rowsupdated++
}
return value
})
.then(function(value) {
console.log('four');
// Render the web page
if (rowinserted != sizeslug.length) {
req.flash('error', error)
res.redirect('/admin/inventory/product/stock/add/' + req.params.id)
} else {
req.flash('success', 'Data added successfully!')
res.redirect('/admin/inventory/product/stock/add/' + req.params.id)
}
})
.catch(function(error) {
console.log('error');
// Error handler
for (var i = 0; i < rowinserted; i++) {
let sql = `DELETE FROM product_tbl WHERE product_sku = ?`
db.query(sql, [stock_id[i]], (error, results, fields) => {
if (error) throw error
})
sql = `DELETE FROM stocks_tbl WHERE product_sku = ?`
db.query(sql, [batch_id[i]], (error, results, fields) => {
if (error) throw error
})
}
res.redirect('/admin/inventory/product/stock/add/' + req.params.id)
})
})
My log returns:
one
two
error
Edit: The process stops (I'm not sure the specific line but according to the log output) after console.log('two') because I tried putting some log as well after the for loops but they don't proceed there. It just go to the .catch/error.
Instead of outputting a string in console.log('error'); dump out an actual error object that you receive in the catch handler. It will give additional details of why and where it fails. I suspect that the code after console.log('two'); throws an exception and then you unintentionally swallow it below.
Consider splitting your code into separate thematic functions. That way you will be able to maintain and spot the errors (or typos) much easier.
Looking at the output, i can see that console.log(product_sku); this is not getting printed. So, actually the problem is var initial_stock = initial_stock[x]. You have declared the local variable(to your then callback function) with same name as global variable(to your route.post callback functions) and now your global initial_stock variable is masked with local one, which is not an array (actually is undefined). So try changing the variable name to something else in your then block and see if problem disappear.
Hope this helps.

Push into an array from foreach and make it available outside foreach

I stuck by looping through an array that receive values from a promise and push values into a new array which is available outside the foreach.
What i have:
app.post('/submit', function (req, res) {
uploadPics(req, res, function (err) {
if (err instanceof multer.MulterError) {
res.send(JSON.stringify({UploadResult: err.message}));
console.log(err.message + ' ' +'Redirect /home');
} else if (err) {
console.log(err);
} else {
res.send(JSON.stringify({UploadResult: 'Success'}));
var filesarray = req.files;
var picinfos = [];
filesarray.forEach(function(file){
GetFileMetaInfo.filemetainfo(file.path).then(function (metadata){
//Stuck here! Can push values into an array (picinfos) but only available in the foreach. not outside..
})
})
//I need picinfos array here....
}
})
})
How i receive my metadata:
var exif = require('exif-parser');
var fs = require('fs');
exports.filemetainfo = function (filepath) {
return new Promise((resolve) => {
var file = filepath;
var buffer = fs.readFileSync(file);
var parser = exif.create(buffer);
var result = parser.parse();
resolve (result);
}).then(function (metadata){
if (metadata.tags.CreateDate !== undefined){
date = new Date (metadata.tags.CreateDate*1000);
datevalues = [
date.getFullYear(),
date.getMonth()+1,
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds(),
];
CreateDate = date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate();
CreateTime = date.getHours()+':'+date.getMinutes()+':'+date.getSeconds();
console.log("CrDate:" +CreateDate, "CrTime:" +CreateTime );
} else {
console.log("No Metadata Creation Infos found in " +filepath);
CreateDate = "";
CretaeTime = "";
}
if (metadata.tags.GPSLatitude !== undefined){
GPSLat = metadata.tags.GPSLatitude;
GPSLon = metadata.tags.GPSLongitude;
console.log("GPSLat:" + GPSLat , "GPSLon:" +GPSLon);
}
else {
console.log("No Metadata GPS Infos found in " +filepath)
GPSLat = "";
GPSLon = "";
}
return MetaData = {
GPSLat: GPSLat ,
GPSLon: GPSLon,
CreateDate: CreateDate,
CreateTime: CreateTime,
}
})
}
May i ask someone to give a hand. How can i make my array available outside the foreach. thank you very much!
The reason you're getting empty array at the end of forEach is because, GetFileMetaInfo.filemetainfo() returns a promise and forEach won't wait for async actions.
You could use async/await with for...of loop to get your desired result.
app.post('/submit', function (req, res) {
uploadPics(req, res, async function (err) { // note async here
if (err instanceof multer.MulterError) {
res.send(JSON.stringify({UploadResult: err.message}));
console.log(err.message + ' ' +'Redirect /home');
} else if (err) {
console.log(err);
} else {
res.send(JSON.stringify({UploadResult: 'Success'}));
var filesarray = req.files;
var picinfos = [];
for(let file of filesarray) {
const metadata = await GetFileMetaInfo.filemetainfo(file.path);
// push metadata into your array here
picinfos.push(metadata);
}
// You will have picinfos here
}
})
})
Although the question is already answered by Dinesh Pandiyan there are still some adjustments that can be made. The following code in his answer runs sequential, meaning that every async request is made after the previously returned result is resolved.
for(let file of filesarray) {
const metadata = await GetFileMetaInfo.filemetainfo(file.path);
// ^- pauses the execution of the current running code
// push metadata into your array here
picinfos.push(metadata);
}
async call #1 ╌╌await╌╌> async call #2 ╌╌await╌╌> async call #3 ╌╌await╌╌> result
You could make the code concurrent by first executing all async statements and then wait until all results are resolved. This can be done by simply changing the following:
// execute all the async functions first, reducing the wait time
for(let file of filesarray) {
const metadata = GetFileMetaInfo.filemetainfo(file.path);
// ^- remove the await
// push metadata into your array here
picinfos.push(metadata);
}
// wait for all results to be resolved
picinfos = await Promise.all(picinfos);
// ^- instead await here
async call #1 ╌╌┐
async call #2 ╌╌┼╌╌await all╌╌> result
async call #3 ╌╌┘
The above could be further simplified by simply using an Array.map() in combination with the already shown Promise.all().
var filesarray = req.files;
var picinfos = await Promise.all(filesarray.map(file => {
return GetFileMetaInfo.filemetainfo(file.path);
}));
// picinfos should be present
Or if you want to avoid working with async/await:
var filesarray = req.files;
Promise.all(filesarray.map(file => {
return GetFileMetaInfo.filemetainfo(file.path);
})).then(picinfos => {
// picinfos should be present
});

Categories

Resources