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);
}
});
Related
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.
I have a problem with my API that sends metadata when called from my smart contract of website. Its NFT tokens and my database is postgres and API is node.js
The problem is when I mint 1 NFT metadata works perfect, but if I mint 2 or more it will only ever send 1 chunk of data? So only 1 NFT will mint properly and the rest with no data?
Do I need to set a loop function or delay? Does anyone have any experience with this?
Any help would be much appreciated.
Below is the code from the "controller" folder labeled "nft.js"
const models = require("../../models/index");
const path = require("path");
const fs = require("fs");
module.exports = {
create_nft: async (req, res, next) => {
try {
const dir = path.resolve(__dirname + `../../../data/traitsfinal.json`);
const readCards = fs.readFileSync(dir, "utf8");
const parsed = JSON.parse(readCards);
console.log("ya data ha final ??", parsed);
parsed.forEach(async (item) => {
// return res.json(item)
let newNft = await models.NFT.create({
name: item.Name,
description: item.Description,
background: item.Background,
body: item.Body,
mouth: item.Mouth,
eyes: item.Eyes,
head_gear: item.Head_Gear,
tokenId: item.tokenId,
image: item.imagesIPFS,
});
});
return res.json({
data: "nft created",
error: null,
success: true,
});
} catch (error) {
console.log("server error", error.message);
next(error);
}
},
get_nft: async (req, res, next) => {
try {
const { id } = req.params;
// console.log("id ?????????",id)
// console.log("type of ",typeof(id))
// const n=Number(id)
// console.log("type of ",typeof(id))
const nft = await models.NFT.findByPk(id);
if (!nft) {
throw new Error("Token ID invalid");
}
if (!nft.isMinted) {
throw new Error("Token not minted");
}
console.log(nft);
// }
const resObj = {
name: nft.name,
description: nft.description,
image: `https://gateway.pinata.cloud/ipfs/${nft.image}`,
attributes: [
{ trait_type: "background", value: `${nft.background}` },
{ trait_type: "body", value: `${nft.body}` },
{ trait_type: "mouth", value: `${nft.mouth}` },
{ trait_type: "eyes", value: `${nft.eyes}` },
{ trait_type: "tokenId", value: `${nft.tokenId}` },
{
display_type: "number",
trait_type: "Serial No.",
value: id,
max_value: 1000,
},
],
};
return res.json(resObj);
} catch (error) {
console.log("server error", error.message);
next(error);
}
},
get_nft_all: async (req, res, next) => {
try {
// console.log("id ?????????",id)
// console.log("type of ",typeof(id))
// const n=Number(id)
// console.log("type of ",typeof(id))
const nft = await models.NFT.findAndCountAll({
limit: 10
});
// console.log(nft);
if (!nft) {
throw new Error("Token ID invalid");
}
// if (nft.isMinted) {
// throw new Error("Token not minted");
// }
// console.log(nft);
// }
var resObjarr = [];
for (var i = 0; i < nft.rows.length; i++) {
resObj = {
name: nft.rows[i].name,
description: nft.rows[i].description,
image: `https://gateway.pinata.cloud/ipfs/${nft.rows[i].image}`,
attributes: [
{ trait_type: "background", value: `${nft.rows[i].background}` },
{ trait_type: "body", value: `${nft.rows[i].body}` },
{ trait_type: "mouth", value: `${nft.rows[i].mouth}` },
{ trait_type: "eyes", value: `${nft.rows[i].eyes}` },
{ trait_type: "tokenId", value: `${nft.rows[i].tokenId}` },
{
display_type: "number",
trait_type: "Serial No.",
value: nft.rows[i].id,
max_value: 1000,
},
],
};
resObjarr.push(resObj);
}
console.log(JSON.stringify(resObjarr))
return res.json(resObjarr);
} catch (error) {
console.log("server error", error.message);
next(error);
}
},
mint: async (req, res, next) => {
try {
const { id } = req.params;
const updated = await models.NFT.findByPk(id);
if (!updated) {
throw new Error("NFT ID invalid");
}
if (updated.isMinted) {
throw new Error("NFT Already minted");
}
updated.isMinted = true;
updated.save();
return res.json({
data: "Token minted successfully",
error: null,
success: true,
});
} catch (error) {
console.log("server error", error.message);
next(error);
}
},
};
Below is from the routes folder.
const router = require("express").Router();
const auth=require("../middleware/auth")
const {
create_nft,
get_nft,
get_nft_all,
mint
} = require("../controller/nft");
router.post(
"/create",
create_nft
);
router.get(
"/metadata/:id",
get_nft
);
router.get(
"/metadata",
get_nft_all
);
router.put(
"/mint/:id",
mint
);
module.exports = router;
Looking your code,you may having some kind of asyncrhonous issue in this part:
parsed.forEach(async (item) => {
// return res.json(item)
let newNft = await models.NFT.create({
name: item.Name,
description: item.Description,
background: item.Background,
body: item.Body,
mouth: item.Mouth,
eyes: item.Eyes,
head_gear: item.Head_Gear,
tokenId: item.tokenId,
image: item.imagesIPFS,
});
});
Because .forEach is a function to be used in synchronous context and NFT.create returns a promise (that is async). So things happens out of order.
So one approach is to process the data first and then perform a batch operation using Promise.all.
const data = parsed.map(item => {
return models.NFT.create({
name: item.Name,
description: item.Description,
background: item.Background,
body: item.Body,
mouth: item.Mouth,
eyes: item.Eyes,
head_gear: item.Head_Gear,
tokenId: item.tokenId,
image: item.imagesIPFS,
})
})
const results = await Promise.all(data)
The main difference here is Promise.all resolves the N promises NFT.create in an async context in paralell. But if you are careful about the number of concurrent metadata that data may be too big to process in parallel, then you can use an async iteration provided by bluebird's Promise.map library.
const Promise = require('bluebird')
const data = await Promise.map(parsed, item => {
return models.NFT.create({
name: item.Name,
description: item.Description,
background: item.Background,
body: item.Body,
mouth: item.Mouth,
eyes: item.Eyes,
head_gear: item.Head_Gear,
tokenId: item.tokenId,
image: item.imagesIPFS,
})
})
return data
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}`);
});
});
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
i will get the Array of Answers
but how to get the Answered users info;
the flow is Get List of Posts, Post User Info, Post User Followers Count, Post Likes Count, Login User Liked The Post True or False,
Answers, Answered User Info and Answered User Followers Count
exports.GetPostList = function(req, res) {
var SkipCoun = 0;
SkipCoun = parseInt(req.params.Limit) * 10;
QuestionsPostModel.QuestionsPostType.find({}, {} , {sort:{createdAt : -1}, skip: SkipCoun, limit: 10 }, function(err, result) {
if(err) {
res.status(500).send({status:"False", message: "Some error occurred while Find Following Users ."});
} else {
const GetUserData = (result) =>
Promise.all(
result.map(info => getPostInfo(info))
).then(
results => {
let [UserInfo, UserFollowers, PostRatingCount, UserRatedCount, AnswersCount, AswersArray ] =
results.reduce(([allOne, allTwo, allThree, allFour, allFive, allSix ], [one, two, three, four, five, six]) =>
[allOne.concat([one]), allTwo.concat([two]), allThree.concat([three]), allFour.concat([four]), allFive.concat([five]), allSix.concat([six])], [ [], [], [], [], [], [] ]);
res.send({ status: "True", UserInfo: UserInfo, UserFollowers: UserFollowers, PostRatingCount: PostRatingCount, UserRatedCount: UserRatedCount, AnswersCount:AnswersCount, AswersArray:AswersArray })
}
).catch(err => res.send({ status: "Fale",Error: err}) );
const getPostInfo = info =>
Promise.all([
UserModel.UserType.findOne({'_id': info.UserId }, usersProjection).exec(),
FollowModel.FollowUserType.count({'UserId': info.UserId}).exec(),
RatingModel.QuestionsRating.count({'PostId': info._id , 'ActiveStates':'Active' }).exec(),
RatingModel.QuestionsRating.count({'UserId': req.params.UserId, 'PostId': info._id, 'PostUserId': info.UserId, 'ActiveStates':'Active'}).exec(),
AnswerModel.QuestionsAnwer.count({'PostId': info._id , 'ActiveStates':'Active' }).exec(),
AnswerModel.QuestionsAnwer.find({ 'PostId':info._id }, 'AnswerText UserId Date' ).exec()
]);
GetUserData(result);
}
});
};
How to Get The Result
as you formed the array, and you are passing it inside Promise.all() .
and you just need the data.
Promise.all() docs.
see Below Code (we can just do as promise .then() and .catch()):
exports.GetPostList = function (req, res) {
var SkipCoun = 0;
SkipCoun = parseInt(req.params.Limit) * 10;
QuestionsPostModel.QuestionsPostType.find({}, {}, { sort: { createdAt: -1 }, skip: SkipCoun, limit: 10 }, function (err, result) {
if (err) {
res.status(500).send({ status: "False", message: "Some error occurred while Find Following Users ." });
} else {
const GetUserData = (result) =>
Promise.all(
result.map(info => getPostInfo(info))
).then(
results => {
let [UserInfo, UserFollowers, PostRatingCount, UserRatedCount, AnswersCount, AswersArray] =
results.reduce(([allOne, allTwo, allThree, allFour, allFive, allSix], [one, two, three, four, five, six]) =>
[allOne.concat([one]), allTwo.concat([two]), allThree.concat([three]), allFour.concat([four]), allFive.concat([five]), allSix.concat([six])], [[], [], [], [], [], []]);
res.send({ status: "True", UserInfo: UserInfo, UserFollowers: UserFollowers, PostRatingCount: PostRatingCount, UserRatedCount: UserRatedCount, AnswersCount: AnswersCount, AswersArray: AswersArray })
}
).catch(err => res.send({ status: "Fale", Error: err }));
const getPostInfo = info =>
Promise.all([
UserModel.UserType.findOne({ '_id': info.UserId }, usersProjection).exec(),
FollowModel.FollowUserType.count({ 'UserId': info.UserId }).exec(),
RatingModel.QuestionsRating.count({ 'PostId': info._id, 'ActiveStates': 'Active' }).exec(),
RatingModel.QuestionsRating.count({ 'UserId': req.params.UserId, 'PostId': info._id, 'PostUserId': info.UserId, 'ActiveStates': 'Active' }).exec(),
AnswerModel.QuestionsAnwer.count({ 'PostId': info._id, 'ActiveStates': 'Active' }).exec(),
AnswerModel.QuestionsAnwer.find({ 'PostId': info._id }, 'AnswerText UserId Date').exec()
]).then(data => {
let userData = data[0];
let followCount = data[1];
let ratingCount = data[2];
let ratingCountBy_postId = data[3];
let answerCount = data[4];
let answers = data[5];
// now you may need to construct some object or something and pass data as you required.
let result = {
user: userData,
follow_count: followCount,
rating_count: ratingCount,
rating_countBy_postId: ratingCountBy_postId,
answer_count: answerCount,
answers: answers
};
}).catch(error => {
console.log(error)
})
GetUserData(result);
}
});
};
exports.GetPostList = function (req, res) {
var SkipCoun = 0;
SkipCoun = parseInt(req.params.Limit) * 10;
QuestionsPostModel.QuestionsPostType.find({}, {}, { sort: { createdAt: -1 }, skip: SkipCoun, limit: 10 }, function (err, result) {
if (err) {
res.status(500).send({ status: "False", message: "Some error occurred while Find Following Users ." });
} else {
const GetUserData = (result) =>
Promise.all(
result.map(info => getPostInfo(info))
).then( result =>{ console.log(result); res.send({ status: "True", data: result }) }
).catch(err => res.send({ status: "False", Error: err }));
const getPostInfo = info =>
Promise.all([
UserModel.UserType.findOne({ '_id': info.UserId }, usersProjection).exec(),
FollowModel.FollowUserType.count({ 'UserId': info.UserId }).exec(),
RatingModel.QuestionsRating.count({ 'PostId': info._id, 'ActiveStates': 'Active' }).exec(),
RatingModel.QuestionsRating.count({ 'UserId': req.params.UserId, 'PostId': info._id, 'PostUserId': info.UserId, 'ActiveStates': 'Active' }).exec(),
AnswerModel.QuestionsAnwer.count({ 'PostId': info._id, 'ActiveStates': 'Active' }).exec(),
AnswerModel.QuestionsAnwer.find({ 'PostId': info._id }, 'AnswerText UserId Date').exec()
]).then(data => {
let UserData = data[0];
let followCount = data[1];
let ratingCount = data[2];
let UserRating = data[3];
let AnswerCount = data[4];
let Answerdata = data[5];
var AnswersArray= new Array();
return GetAnsUserData();
async function GetAnsUserData(){
for (let ansInfo of Answerdata) {
await getAnswerInfo(ansInfo);
}
let result = {
_id: info._id,
UserId: UserData._id,
UserName: UserData.UserName,
UserCategoryId: UserData.UserCategoryId,
UserCategoryName: UserData.UserCategoryName,
UserImage: UserData.UserImage,
UserCompany: UserData.UserCompany,
UserProfession: UserData.UserProfession,
Followers:followCount,
PostTopicId: info.PostTopicId,
PostTopicName: info.PostTopicName,
PostDate: info.PostDate,
PostText: info.PostText ,
PostLink: info.PostLink,
PostImage: info.PostImage,
PostVideo: info.PostVideo,
RatingCount: ratingCount,
UserRating: UserRating,
AnswersCount: AnswerCount,
Answers: AnswersArray,
};
return result;
}
function getAnswerInfo(ansInfo){
return new Promise(( resolve, reject )=>{
UserModel.UserType.findOne({'_id': ansInfo.UserId }, usersProjection, function(err, AnsUserData) {
if(err) {
res.send({status:"Fale", Error:err });
reject(err);
} else {
FollowModel.FollowUserType.count({'UserId': AnsUserData._id}, function(newerr, count) {
if(newerr){
res.send({status:"Fale", Error:newerr });
reject(newerr);
}else{
var newArray = [];
newArray.push( {
_id: ansInfo._id,
UserId: AnsUserData._id,
UserName: AnsUserData.UserName,
UserCategoryId: AnsUserData.UserCategoryId,
UserCategoryName: AnsUserData.UserCategoryName,
UserImage: AnsUserData.UserImage,
UserCompany: AnsUserData.UserCompany,
UserProfession: AnsUserData.UserProfession,
Followers: count,
Date: ansInfo.Date,
PostId: ansInfo.PostId,
PostUserId: ansInfo.PostUserId ,
AnswerText: ansInfo.AnswerText
}
);
AnswersArray.push(newArray[0]);
resolve(newArray[0]);
}
});
}
});
});
}
}).catch(error => {
console.log(error)
})
GetUserData(result);
}
});
};
Finally I get The Answer
Thanks To ALL