NodeJS nested promises not working properly - node.js

I got a problem with my code.It jumps to second .then section without completing first job. After that, it goes back to first promise but never executes code inside second .then
Promise.all(jobs).then((values) => {
console.log("First!")
values.forEach(function(vals) {
vals.forEach(function(doc) {
if (doc.properties.location_i.toString() == request.body.id) {
jobs_do.push(dbo.collection("zones").find({
"geometry": {
$geoIntersects: {
$geometry: {
type: "Point",
coordinates: [
docs[values.indexOf(vals)].geometry_do.coordinates[0],
docs[values.indexOf(vals)].geometry_do.coordinates[1]
]
}
}
}
}))
}
})
})
}).then(function() {
console.log("Second!")
Promise.all(jobs_do).then((values) => {
values.forEach(function(vals) {
vals.forEach(function(doc) {
console.log(doc.properties.objectid);
});
})
});
});
It fulfills jobs_do array but Promise.all(jobs_do).then((values)) executed once when jobs_do is empty.
Console log is:
First!
Second!

Although I can't exactly replicate the setup you have above, here's a simple example that should guide you how to re-write your code so that it works as it's supposed to.
const jobs = Array.from({ length: 2 })
.map((_, idx) => {
return Promise.resolve({
id: idx + 1,
title: `Job ${idx + 1}`
})
})
const jobs_do = [];
Promise.all(jobs)
.then(values => {
console.log("first!");
for (const value of values) {
if (true) {
jobs_do.push(
Promise.resolve({
...value,
description: `This is a description for job ${value.id}`
})
);
}
}
return Promise.all(jobs_do);
})
.then(results => {
console.log("second!");
results.forEach(result => {
console.log(`[${result.id}] | ${result.title} | ${result.description}`);
});
});

Related

NodeJS Array not filling up

Im using mongodb as a database after getting the valuation data which are more then one , i loop inside them and get the offers according to the offres_id , I asure you that the database has data inside and to querys are working correctly in fact if i console log them in each iteration i get this result
{
offre: [
{
_id: new ObjectId("63320bf87123db5691c51392"),
user_id: '63304e44aa63c519d887dac1',
brand: 'HP',
model: 'AZGGH-89855A',
photo: '16642242480661659650294043-bs-5.png',
scan_method: 'manual',
__v: 0
}
],
valuation: {
_id: new ObjectId("63320d39a5677df3cebcbdae"),
user_id: '63304e44aa63c519d887dac1',
offre_id: '63320bf87123db5691c51392',
given_price: '1236',
comment: 'no comment',
__v: 0
}
}
{
offre: [
{
_id: new ObjectId("6334202a8c7e6d90b35ee999"),
user_id: '63304e44aa63c519d887dac1',
brand: 'DELL',
model: 'AZGGH-89855A',
photo: '1664360490280Capture.PNG',
scan_method: 'manual',
__v: 0
}
],
valuation: {
_id: new ObjectId("633420be8c7e6d90b35ee99e"),
user_id: '63304e44aa63c519d887dac1',
offre_id: '6334202a8c7e6d90b35ee999',
__v: 0
}
}
but when i try storing each offre & valuation at the same array cell and return it i get this as a result
[]
However this is the code
router.get('/get', async (req, res) => {
try {
Valuation.find({ user_id: req.session.userID })
.exec()
.then(valuation => {
let myData = [];
if (valuation) {
for (let i = 0; i < valuation.length; i++) {
Offre.find({_id : valuation[i].offre_id})
.exec()
.then(offre=>{
myData.push({offre : offre, valuation : valuation[i]})
})
}
res.status(200).json(myData)
} else {
res.status(404).json('no valuations found')
}
})
.catch(error => {
res.status(500).json(error.message)
})
} catch (error) {
res.status(500).json({ error: error.message })
}
})
Since you're already using async, it would be a shame to not use await to simplify your code:
router.get("/get", async (req, res) => {
try {
const valuation = await Valuation.find({ user_id: req.session.userID }).exec();
if (valuation) {
let myData = [];
for (let i = 0; i < valuation.length; i++) {
const offre = await Offre.find({ _id: valuation[i].offre_id }).exec();
myData.push({ offre: offre, valuation: valuation[i] });
}
res.status(200).json(myData);
} else {
res.status(404).json("no valuations found");
}
} catch (error) {
res.status(500).json({ error: error.message });
}
});
You can probably also speed up the Offre query by using an $in query to retrieve all offres with one query, but that's another thing.

Axios Keeps setting my content type as multipart/form-data; boundary=----WebKitFormBoundary When I have JSON data

I have tried many things including adding the headers to the request. Still does not work. I have looked everywhere and came here as a last resort.
My main.js (routes)
app.post("/timeclock/punchout", async (req, res) => {
let time = moment().unix();
let employeeid = req.body.empid2;
let date = moment().format();
let comments = req.body.comments;
return res.send({ error: false, message: "complete punch" });
});
my liquid file using jQuery and axios
<script>
toast = siiimpleToast.setOptions({
container: 'body',
class: 'siiimpleToast',
position: 'top|right',
margin: 15,
delay: 2,
duration: 3000,
style: {},
})
$("#form").submit(function(event) {
event.preventDefault()
let empid1 = $("#empid").val()
let comments1 = $("#comments").val()
axios.post('/timeclock/punchin', {comments: comments1, empid: empid1}).then(response => {
if(response.data.error == false) {
$("#form").trigger('reset')
toast.success('Punch Successful!')
} else if(response.data.error == true) {
toast.alert(response.data.message)
$("#form").trigger('reset')
}
}, (error) => {
console.log(error)
})
})
$("#form").submit(function(event) {
event.preventDefault()
let empid1 = $("#empid").val()
let commentsout1 = $("#commentsout").val()
axios.post('/timeclock/punchout', {commentsout: commentsout1, empid: empid1}).then(response => {
if(response.data.error == false) {
$("#form").trigger('reset')
toast.success('Punch Successful!')
} else if(response.data.error == true) {
toast.alert(response.data.message)
$("#form").trigger('reset')
}
}, (error) => {
console.log(error)
})
})
any ideas? I read that it automatically detects the content type. But I cant seem to override it.

Typeorm find options with order and where

I would like to order this find function through the table relation.
const [people, total] = await typePersonServiceInstance.find(
{
take,
skip,
where: (qb: any) => {
qb.where('person.type IN (:...type)', { type });
qb.andWhere('person.status IN (:...status)', { status });
if (query.search) {
qb.andWhere(new Brackets((subQb) => {
subQb.where('name like :name', { name: `%${query.search}%` });
subQb.orWhere('fantasyName like :fantasyName', { fantasyName: `%${query.search}%` });
subQb.orWhere('person.city like :city', { city: `%${query.search}%` });
subQb.orWhere('person.state like :state', { state: `%${query.search}%` });
subQb.orWhere('person.id = :id', { id: query.search });
}));
}
},
order: {
person: {
status: 'ASC'
}
}
},
);
The issue i'm facing is when trying to order by some attribute from person table, if I do
order: {
anyColumnFromTypePersonHere: 'ASC' | 'DESC'
}
It works pretty fine, but if I want to order by status (that is an attribute from person) it will not work
Just add this line:
qb.addOrderBy('person.status', "ASC") ;

XState: Wait for response of invoked function

I am planning to use XState for managing states in the backend of my application. When an api is called, a function will be called on successful state change. The result of the function call has to be returned as response of the api.
// Returns a Promise, e.g.:
// {
// id: 42,
// name: 'David',
// friends: [2, 3, 5, 7, 9] // friend IDs
// }
function getUserInfo(context) {
return fetch('/api/users/#{context.userId}').then(response =>
response.json()
);
}
// Returns a Promise
function getUserFriends(context) {
const { friends } = context.user;
return Promise.all(
friends.map(friendId =>
fetch('/api/users/#{context.userId}/').then(response => response.json())
)
);
}
const friendsMachine = Machine({
id: 'friends',
context: { userId: 42, user: undefined, friends: undefined },
initial: 'gettingUser',
states: {
gettingUser: {
invoke: {
src: getUserInfo,
onDone: {
target: 'gettingFriends',
actions: assign({
user: (context, event) => event.data
})
}
}
},
gettingFriends: {
invoke: {
src: getUserFriends,
onDone: {
target: 'success',
actions: assign({
friends: (context, event) => event.data
})
}
}
},
success: {
type: 'final'
}
}
});
interpret(friendsMachine).start()
I want the output of this of getUserFriends sent as a response from my api. How to wait for the transition and all the invocations to be completed?
You can use onDone (read the docs on invoking promises 📖)
Here's an example Express app that waits sequentially for 2 promises to finish, and then sends that data:
function eventuallyGet(value) {
return new Promise(res => {
setTimeout(() => {
res(value);
}, 1000)
})
}
const getUserMachine = Machine({
initial: 'fetchingName',
context: {
user: undefined
},
states: {
fetchingName: {
invoke: {
src: () => eventuallyGet('David'),
onDone: {
target: 'fetchingDetails',
actions: assign({
user: (ctx, e) => ({
...ctx.user,
name: e.data
})
})
}
}
},
fetchingDetails: {
invoke: {
src: () => eventuallyGet({ location: 'Florida' }),
onDone: {
target: 'success',
actions: assign({
user: (ctx, e) => ({
...ctx.user,
...e.data
})
})
}
}
},
success: {
type: 'final',
data: {
user: ctx => ctx.user
}
}
}
});
app.get('/user', function(request, response) {
interpret(getUserMachine)
.onDone(e => {
response.json(e.data);
})
.start();
});
You can see the code here: https://glitch.com/~pleasant-relish

NoedJS forEach with add new element on a http-request

how to add new element in an array with a http request.
I have a code like this but it doesn't add new element because of async on nodejs and I don't know how can I pass it.
arr = [
{ id: 123},
{ id: 124},
{ id: 125},
{ id: 126},
]
arr.forEach(function(row, index) {
request.post('/test')
.then((data) => {
row.status = "success"
})
.catch((error) => {
row.status = "failed"
});
});
so that i can achieve something like this.
[
{ id: 123, status: 'success' },
{ id: 124, status: 'failed' },
{ id: 125, status: 'failed' },
{ id: 126, status: 'success' },
]
I'm new in NodeJs. thank you guys
You have to use Promise.all because you're handling several promises:
let arr = [
{ id: 123},
{ id: 124},
{ id: 125},
{ id: 126}
]
Promise.all(arr.map((row, index) => {
return request.post('/test')
.then(data => {
row.status = "success"
})
.catch(error => {
row.status = "failed"
});
})).then(() => console.log(arr))
You can try this popular node module Async. Try this .each here http://caolan.github.io/async/docs.html#each.
async.each(arr, _your_function, (err) => {
// check success
})
_your_function(){}
use async.eachOf, you can access element and index in the array.
var async = require("async");
var arr = [
{ id: 123},
{ id: 124},
{ id: 125},
{ id: 126},
];
async.eachOf(arr, function(e, i, ecb){
request.post('/test',)
.then( (data) => {
e.status = "success"
return ecb(null);
})
.catch( (error) => {
e.status = "failed"
return ecb(null);
});
}, function(err){
if(err)
{
console.log("err");
}
else
{
console.log(arr);
}
});

Resources