My two variables are not equal sometimes but must be - node.js

My two variable "soundTypeFound[0].name" and "req.soundTypes[iteration]" must be the same everytime but once in five times its coming as false.
I think the loop goes more quickly than the function "allSoundTypeQuery.GetSoundTypeByName(item, (soundTypeFound, err) => {}" and the variable "iteration" does not have the time to be incremented as same time as the loop.
Thank you for your help
async function checkSoundTypes (req, res, soundTypesString, error, next) {
let stop = false;
req.soundTypes = soundTypesString.split(',');
let iteration = 0;
for (let item of req.soundTypes) {
await allSoundTypeQuery.GetSoundTypeByName(item, (soundTypeFound, err) => {
if (err) {
return res.status(500).json({"error": "Cannot find the sound type in the DB"});
}
if (soundTypeFound.length <= 0 || soundTypeFound[0].name !== req.soundTypes[iteration]) {
stop = true;
}
iteration++;
if (iteration === req.soundTypes.length) {
if (stop === true) {
error.push("soundTypes");
return res.status(400).json(error);
}else if (err) {
return res.status(400).json(error);
}else {
next();
}
}
});
}
}

Since you were sending a callback function, it will not wait and move forward with the next iteration, so it causing error,now the method will return promise as we are using promisify method of the util module, not it will wait for the promise to resolve and then move to the next line.
const {promisify} = require('util');
async function checkSoundTypes (req, res, soundTypesString, error, next) {
let stop = false;
req.soundTypes = soundTypesString.split(',');
let iteration = 0;
for (let item of req.soundTypes) {
const getSoundTypeByName = promisify(allSoundTypeQuery.GetSoundTypeByName);
const soundTypeFound= await getSoundTypeByName(item);
if (!soundTypeFound) { // this you should check as per your response
return res.status(500).json({"error": "Cannot find the sound type in the DB"});
}
if (soundTypeFound.length <= 0 || soundTypeFound[0].name !== req.soundTypes[iteration]) {
stop = true;
}
iteration++;
if (iteration === req.soundTypes.length) {
if (stop === true) {
error.push("soundTypes");
return res.status(400).json(error);
}else if (err) {
return res.status(400).json(error);
}else {
next();
}
}
}
}

Related

How to return 2 arrays after saving data to mongodb using node js

I need help with code below. I get an array of items from the client then the goal is to save them in mongodb and return the list classified as 'saved' and 'failed' items. sample of failed items are those that are duplicate on a unique attribute.
I know the code below will not work because of variable scope. how do i get around it? the code below returns an empty array for both savedItems and failedItems. Thanks!
router.post('/addItems', async (req, res, next) => {
let items = req.body;
let result = {
savedItems: [],
failedItems: []
};
function saveData() {
for (i = 0; i < items.length; i++) {
item = items[i];
Model.create({ ...item }, (err, data) => {
if (err) {
result.failedItems.push(item);
} else {
result.savedItems.push(item);
}
});
}
return result;
}
saveData().then(result => {
res.send({
results: result
});
});
});
router.post('/addItems', async (req, res, next) => {
// use try catch when use async
try {
let items = req.body;
let result = {
savedItems: [],
failedItems: []
};
for (let i = 0; i < items.length; i++) {
const item = items[i];
// use the returned promise instead of callback for Model.create
const data = await Model.create({ ...item });
result.savedItems.push(item);
// if also need to handle failed item in result use anathor try catch inside
/*try {
const data = await Model.create({ ...item });
result.savedItems.push(item);
} catch( err ) {
result.failedItems.push(item);
}*/
}
res.send({
results: result
});
} catch( err ) {
// To all the errors unexpected errors + thrown rejected promises
res.send({
error: err
});
}
});
Your saveData method didn't return a promise, try this
function saveData() {
return new Promise(resolve => {
let items = req.body;
let result = {
savedItems: [],
failedItems: []
};
let promises = [];
for (i = 0; i < items.length; i++) {
item = items[i];
let promise = new Promise(resolve => {
Model.create({ ...item }, (err, data) => {
if (err) {
result.failedItems.push(item);
} else {
result.savedItems.push(item);
}
resolve();
});
});
promises.push(promise);
}
Promise.all(promises).then(() => resolve(result));
})
}

Node's promisify is not working with callback-based function

I am having a function which does some async processing and I want to convert it to a promise, so that I can make a "chain of execution" with other depended functions later on.
Below is the code(slightly modified for privacy):
router.get('/api/prx/ptr', function(req, res) {
let prx = req.params.prx_id
let ptr = {}
let parse_text = (idx_array, prx) => {
for(let name of idx_array) {
if (typeof ptr[name] === 'undefined') {
ptr[name] = []
}
get_text(prx, name, (tg) => {
const pst = new Set(tg.ph.map(ps => ps.label))
pst.forEach(ps => {
ptr[name].push(ps)
})
})
}
return true
}
parse_text = promisify(parse_text)
documentExists(prx, function(err, dbexists){
if (err) {
console.log(err);
return res.status(404).send(err)
}
get_idx_array(prx, function(err, idx_array){
if (err) {
return res.status(err.code || 400).send(err)
}
idx_array = idx_array.map(function(v){return v._id});
parse_text(idx_array, prx)
.then(result => {
res.status(200).send(ptr)
})
})
})
})
The problem is that in the last line, the promise never resolves and thus the request-response cycle never ends. Not sure what I have done wrong in my setup. Any help appreciated.

Last then function being called multiple times

I'm trying to write a chain of Promises but the last .then() is being called multiple times and I don't know why. The last .then() must run a single time because it will call another API passing result as body.
I know that is being called multiple times because I'm logging as console.log().
What is wrong on my code? For my understand, then() should wait promise returns something.
app.post('/router/join', function(req, res){
let data = req.body;
sessions.validate(data)
.then(result => {
return {
authenticated: (result.code === 201)
};
})
.then(result => {
if(result.authenticated){
return contacts.getContacts(data.tenant_id).then(cs => {
let json = merge(result, cs.data);
return Promise.all(cs.data.items.map(contact => {
return messages.getLastMessage(data.tenant_id, contact.item.contact_id, data.hash_id)
.then(result => {
contact.item.last_message = result.code === 200 && result.data.length > 0 ? result.data[0] : null;
return contact;
});
})).then(result => {
json.items = result;
return json;
});
});
} else {
return result;
}
})
.then(result => {
//this call should run after all other promises and only a single time
let event = result.authenticated ? 'valid_session' : 'invalid_session';
console.log('222');
proxy.send(event, result)}
)
.catch(err => {
console.log('333');
proxy.send('invalid_session', {socket_id: data.socket_id})
})
res.status(201).send({});
});
You can use async/await to clean it up. Inside async functions you can await the results of promises.
app.post('/router/join', async function (req, res, next) {
try {
let data = req.body;
let {code} = await sessions.validate(data);
let result = { authenticated: (code === 201) };
if (result.authenticated) {
let cs = await contacts.getContacts(data.tenant_id);
let json = merge(result, cs.data);
let items = Promise.all(cs.data.items.map(async contact => {
let result = await messages.getLastMessage(data.tenant_id, contact.item.contact_id, data.hash_id)
contact.item.last_message = result.code === 200 && result.data.length > 0 ? result.data[0] : null;
return contact;
}));
json.items = items;
result = json;
}
let event = result.authenticated ? 'valid_session' : 'invalid_session';
console.log('222');
proxy.send(event, result);
res.status(201).send({});
} catch (err) {
proxy.send('invalid_session', {socket_id: data.socket_id})
next (err);
}
});

Nodejs loop through same API with different parameters

I trying to loop through same API result and if the API result is NULL then I want loop through it again few times (i.e 4-5 times) with different parameters and if it's reached the 5th time. I want to exit the loop. The code I'm trying is see below:
var roads = 1000;
var findResult = true;
var loop = 0;
while (findResult) {
result = APIResult(rarray, roads);
if (result !== null) {
findResult = false; // stop the loop
} else if (loop == 5) {
findResult = false; // stop the loop
} else {
roads = roads * 10;
loop++;
}
}
function APIResult(rarray, roads) {
request.post(
env.TEST_URL + 'test/',
{
json: {
//...
roads: roads,
//..
},
},
function(error, response, body) {
if (!error && response.statusCode == 200) {
return JSON.parse(body.rows[0].result);
}
});
}
I'm even tried adding Q promise but didn't worked, any idea how to do it?
Your APIResult function doesn't return anything. This function is asynchronous, so it should return promise or use a callback.
Your code result = APIResult(rarray, roads); sets to result variable undefined value. I think, async/await style for implementing asynchronous JS features will work for you.
Current last Node.js version is 8.1. It has native support for async/await. There is an example, how you can implement your code:
async function main() {
var roads = 1000;
var findResult = true;
var loop = 0;
while (findResult) {
try {
result = await APIResult(rarray, roads);
} catch (e) {
//APIResult reject promise branch
}
if (result !== null) {
findResult = false; // stop the loop
} else if (loop == 5) {
findResult = false; // stop the loop
} else {
roads = roads * 10;
loop++;
}
}
}
async function APIResult(rarray, roads) {
return new Promise((res, rej) => {
request.post(
env.TEST_URL + 'test/',
{
json: {
//...
roads: roads,
//..
},
},
function(error, response, body) {
if (error) return rej(error);
if (response.statusCode === 200) return res(JSON.parse(body.rows[0].result));
});
});
}
main();

How to traverse all files, and support pause and continue

I have created a NodeJS (electron) code for read all the files in a specific directory and subdirectories.
I don't want to use too much HD resources, that why I use a delay of 5ms between folders.
Now my question. I want the if my NODE process stop? I want to be able to continue from when it is stopped. How should I do that?
In other words: How to keep index of current state while walking in all files and folder, so I can continue the traversing from when it has stopped.
Thank you
My Code:
var walkAll=function(options){
var x=0
walk(options.dir,function(){})
function walk(dir,callback) {
var files=fs.readdirSync(dir);
var stat;
async.eachSeries(files,function(file,next){
file=dir +'/' + file
if (dir.match(/Recycle/)) return next()
if (dir.match(/.git/)) return next()
if (dir.match(/node_modules/)) return next()
fs.lstat(file,function(err,stat){
if(err) return next()
if(stat.mode==41398) return next()
if (stat.isDirectory()) {
setTimeout(function(file){
walk(file,next)
}.bind(null,file),5)
}
else{
x++
if(false || x % 1000===0) console.log((new Date().valueOf()-start)/1000,x,file)
next()
}
})
},function(){
callback()
})
}
}
walkAll({
dir:'c:/',
delay:1000
});
Keep a list of sub directories to be visited, and update the list every iteration.
The walk function in the following example takes a previous state, and returns files of next sub directory with next state.
You can save the state before stopping the process, then load the saved state to continue the traversal when restarting.
function walk(state, readdir) {
let files = [], next = [];
while (state.length > 0) {
try {
const current = state.shift()
files = readdir(current).map(file => current + '/' + file)
next = state.concat(files)
break
} catch(e) {}
}
return [next, files]
}
function main() {
const {writeFileSync: writeFile, readdirSync: readdir} = require('fs')
const save = './walk.json'
let state
try {
state = require(save)
} catch(e) {}
if (!state || state.length < 1) state = ['.']
const [nextState, files] = walk(state, readdir)
console.log(files)
writeFile(save, JSON.stringify(nextState, null, 2))
}
main()
an alternate idea,
var miss = require('mississippi')
var fs = require("fs")
var through2 = require("through2")
var path = require("path")
function traverseDir(dirPath) {
var stack = [path.resolve(dirPath)];
var filesStack = []
return miss.from.obj(function(size, next) {
if (filesStack.length) {
return next(null, filesStack.shift())
}
var self = this;
try {
while(stack.length) {
readADir(stack.pop()).forEach(function (f) {
if (f.t=="d") {
stack.push(f.p)
}
filesStack.push(f)
})
if (filesStack.length) {
return next(null, filesStack.shift())
}
}
return next(null, null)
}catch(ex) {
return next(ex)
}
})
}
function readADir (dir) {
return fs.readdirSync(dir)
.map(function (f) {return path.join(dir, f)})
.filter(function (f) { return !f.match(/\.git/) })
.filter(function (f) { return !f.match(/Recycle/)})
.filter(function (f) { return !f.match(/node_modules/)})
.map(function (p) {
try {
var stat = fs.lstatSync(p);
if(stat.mode==41398) return null
var t = stat.isDirectory() ? "d":"f"
return { t: t, p: p }
}catch (ex) {}
return null
})
.filter(function (o) {return o!==null})
}
function loadState(base){
base = path.resolve(base)
var state = {base: base, last:null}
if (fs.existsSync("state.json")) {
state = JSON.parse(fs.readFileSync("state.json"))
} else {
saveState(state)
}
return state
}
function saveState(state){
fs.writeFileSync("state.json", JSON.stringify(state))
}
var state = loadState("..")
var sincePath = state.last;
var filesStream = traverseDir(state.base)
.on('end', function () {
console.log("end")
})
.pipe(through2.obj(function (chunk, enc, next) {
if(!sincePath) this.push(chunk)
if(chunk.p===sincePath) {
sincePath=null
}
next()
}))
var tr = through2.obj(function (chunk, enc, next) {
state.last = chunk.p
saveState(state)
console.log("data %v %j", chunk.t, chunk.p)
this.push(chunk)
setTimeout(next, 500)
}).resume()
require('keypress')(process.stdin);
process.stdin.on('keypress', function (ch, key) {
if(!key) return
if (key.name == "c") {
console.log("continue")
filesStream.pipe(tr)
} else if (key.name=="p") {
console.log("pause")
filesStream.unpipe(tr)
}
});
console.log("Press 'c' to start")

Resources