I have declare the variable first. but if I do console.log(userinsertData) outside looping variable still not fill.
what i should do for solving this problem?
here my code:
var User = require('../models/user');
module.exports = {
myaction: function(req, res, next) {
var data = req.body,
userinsertData = [];
try {
data.forEach(function(item, index) {
var userdata = new User();
userdata.name = item.name;
userdata.age = item.age;
userdata.sex = item.sex;
userdata.save(function(err, data) {
if (err) {
res.send(err)
} else {
userinsertData.push(data);
}
});
})
} catch (e) {
res.json({
message: 'data not valid'
})
}
console.log(userinsertData);
res.json({
message: 'musician created!',
data: userinsertData
});
}
};
you should solve the problem as
async.eachSeries(data, function (info, callback) {
//here process your data and call callback() for next iteration
}, function (err) {
if (err) {
//this will be called after all iterations and in case of error
}else{
console.log('Well done :-!');
//this will be called after all interations successfully
}
});
this problem you are facing is because of asynchronous nature of nodejs and async helps you to introduce blocking.
Don't forget to include async
Use promise
var User = require('../models/user');
module.exports = {
myaction: function(req, res, next) {
var data = req.body,
userinsertData = [];
new Promise(function(resolve, reject) {
data.forEach(function(item, index) {
var userData = new User(item);
userData.save(function(err, data) {
// if error, reject
if(err) return reject(err);
// we have proceed all items in data, resolve it
else if(data.length - 1 === index) return resolve(userinsertData);
// not finished yet, keep proceeding
else userinsertData.push(data);
});
}).then(function(successResult) {
res.json({
message: 'musician created!',
data: successResult
});
}, function(errorResult) {
res.json({
message: 'data not valid'
});
});
}
};
Use callbacks
var User = require('../models/user');
module.exports = {
myaction: function(req, res, next) {
var data = req.body,
userinsertData = [];
function saveUser(callback) {
data.forEach(function(item, index) {
var userData = new User(item);
userData.save(function(err, data) {
// if error, return callback with error
if(err) return callback(err);
// we have proceed all items in data, return data
else if(data.length - 1 === index) callback(null, userinsertData);
// not finished yet, keep proceeding
else userinsertData.push(data);
});
}
saveUser(function(err, users) {
if(err) return res.json({message: 'data not valid'});
res.json({
message: 'musician created!',
data: users
});
});
}
};
This is what async package does internally
Related
My basic POST API makes a call to database , first to authenticate user and then to authentic if the products provided are true. But before productValidation can complete, res.end() is being executed.
As output, I get ::
"validated object"
"stopping the res"
"validated object"
Whereas I am trying to validated and add each cartItem to database and only then send a success response to client.
const express = require("express");
const app = express();
const router = express.Router();
var connection = require("./../database/serverConnector");
router.get("/:userId", (req, res, next) => {
connection.query(
"SELECT * FROM cart_items AS c INNER JOIN product AS p ON c.product_id = p.id WHERE user_id = ?",
[req.params.userId],
function (error, results, fields) {
if (error) throw error;
else {
console.log("Query made for cart of user " + req.params.userId);
res.status(200).send(results);
}
}
);
});
router.post("/:userId", userValidate, (req, res, next) => {
multipleProductValidation(req, res, next).then(function (data) {
res.end();
console.log("stopping the res");
});
// .catch(error){
// console.log(error);
// }
});
function userValidate(req, res, next) {
connection.query(
"SELECT * from user where id = ?",
[req.params.userId],
function (error, user, fields) {
if (error) {
res.status(500).json({
message: error.sqlMessage,
});
} else {
if (user.length == 0) {
res.status(404).json({
message: "User not found with ID " + req.params.userId,
});
} else next();
}
}
);
}
function multipleProductValidation(req, res, next) {
return new Promise(function (resolve, reject) {
req.body.cartItems.forEach((item, i) => {
productValidate(item, req, res, next).then(function (data) {
resolve(data);
console.log("validated object");
//next();
});
});
});
}
function productValidate(item, req, res, next) {
return new Promise(function (resolve, reject) {
connection.query(
"SELECT * from product where id = ?",
[item.product_id],
function (error, product, fields) {
if (error) {
res.status(500).json({
message: error.sqlMessage,
});
} else {
if (product.length == 0) {
res.status(404).json({
message: "Product not found with ID " + item.product_id,
});
resolve(false);
} else {
connection.query(
"INSERT INTO cart_items (product_id,user_id,size,quantity) VALUES (?,?,?,?)",
[item.product_id, req.params.userId, item.size, item.quantity],
function (error, results, fields) {
if (error) {
res.status(500).json({
message: error.sqlMessage,
});
} else {
res.statusText =
"Items added to cart for User " + req.params.userId;
resolve(true);
}
}
);
}
}
}
);
});
}
module.exports = router;
So what is happening here is that you are calling resolve in your multipleProductValidation before you finish processing all the products.
something like this should fix your problem
function multipleProductValidation(req, res, next){
return new Promise(function(resolve, reject) {
let promiseArr = req.body.cartItems.map(item => productValidate(item, req, res, next))
Promise.all(promiseArr).then(values => resolve(values))
}
)}
As i said in the title i am using a npm package called "next-connect" to structure my api. Every api route that i created suffered from this error. This is the error :
Unhandled rejection: TypeError: Cannot read property 'end' of undefined
at next (/var/task/node_modules/next-connect/lib/index.js:43:54)
at next (/var/task/node_modules/next-connect/lib/index.js:49:9)
at next (/var/task/node_modules/next-connect/lib/index.js:58:16)
at next (/var/task/node_modules/next-connect/lib/index.js:49:9)
at next (/var/task/node_modules/next-connect/lib/index.js:58:16)
at next (/var/task/node_modules/next-connect/lib/index.js:58:16)
at next (/var/task/node_modules/next-connect/lib/index.js:60:9)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
After a few minutes of trying i get to solve it in dev. Most of this due to messing with the .env file.
Here the code from my API Route :
import nextConnect from "next-connect";
import bcrypt from "bcryptjs";
import middleware from "../../middlewares/middleware";
const handler = nextConnect();
handler.use(middleware);
handler.get((req, res) => {
if (req.user) {
const { name, email, bio, profilePicture, emailVerified } = req.user;
return res.status(200).send({
status: "ok",
data: {
isLoggedIn: true,
user: {
name,
email,
bio,
profilePicture,
emailVerified
}
}
});
}
return res.status(200).send({
status: "ok",
data: {
isLoggedIn: false,
user: {}
}
});
});
handler.post((req, res) => {
const { email, password } = req.body;
return req.db
.collection("users")
.findOne({ email })
.then(user => {
if (user) {
return bcrypt.compare(password, user.password).then(result => {
if (result) return Promise.resolve(user);
return Promise.reject(Error("The password you entered is incorrect"));
});
}
return Promise.reject(Error("The email does not exist"));
})
.then(user => {
req.session.userId = user._id;
return res.send({
status: "ok",
message: `Welcome back, ${user.name}!`
});
})
.catch(error =>
res.send({
status: "error",
message: error.toString()
})
);
});
handler.delete((req, res) => {
delete req.session.userId;
return res.status(200).send({
status: "ok",
message: "You have been logged out."
});
});
export default handler;
And here code from the next-connect package (the one mentioned in the error report) :
module.exports = () => {
function connect(req, res) {
connect.handle(req, res);
}
connect.stack = [];
function add(method, ...handle) {
for (let i = 0; i < handle.length; i += 1) {
if (handle[i].stack) Object.assign(this.stack, handle[i].stack);
else this.stack.push({ handle: handle[i], method });
}
}
// method routing
connect.get = add.bind(connect, 'GET');
connect.head = add.bind(connect, 'HEAD');
connect.post = add.bind(connect, 'POST');
connect.put = add.bind(connect, 'PUT');
connect.delete = add.bind(connect, 'DELETE');
connect.options = add.bind(connect, 'OPTIONS');
connect.trace = add.bind(connect, 'TRACE');
connect.patch = add.bind(connect, 'PATCH');
// middleware
connect.use = add.bind(connect, '');
connect.error = add.bind(connect, 'ERR');
connect.apply = function apply(req, res) {
return new Promise((resolve) => this.handle(req, res, resolve));
};
connect.handle = function handle(req, res, done) {
let idx = 0;
const { stack } = this;
async function next(err) {
const layer = stack[idx];
idx += 1;
// all done
if (!layer) {
if (done) done();
else if (!res.headersSent) res.writeHead(404).end();
return;
}
// check if is correct method or middleware
if (layer.method !== '' && layer.method !== 'ERR' && layer.method !== req.method) {
next(err);
return;
}
try {
if (!err) { await layer.handle(req, res, next); return; }
// there is an error
if (layer.method === 'ERR' || layer.handle.length === 4) {
await layer.handle(err, req, res, next);
} else next(err);
} catch (error) {
next(error);
}
}
// Init stack chain
next();
};
return connect;
};
I am new in nodejs. I am creating a basic API to get record by id. Everything is working fine. It is returning user data from database. But when i use password variable from response in same function it give me empty value whereas i am getting value in response. I think this is async issue but i dont know how to fix it.
This is API code
var express = require('express');
var db = require('../db/database');
var bcrypt = require('bcrypt');
const router = express.Router();
router.get("/:userId", (req, res, next) => {
let uid = req.params.userId;
db.query(`SELECT * FROM users WHERE u_id = ${uid}`, (err, data)=> {
if(!err) {
if(data && data.length > 0) {
var message = '';
if(data.u_password){
//var pass = data.u_password;
if(bcrypt.compare('123456', data.u_password)) {
// Passwords match
message = 'Passwords match';
} else {
// Passwords don't match
message = 'Passwords dont match';
}
}
res.status(200).json({
message:message,
});
} else {
res.status(200).json({
message:"User Not found."
});
}
}
});
});
database.js
var mysql = require('mysql');
const pool = mysql.createPool({
connectionLimit : 10,
host: 'localhost',
user: 'root',
password: '',
database: 'lost_and_found',
debug : false
});
function executeQuery(sql, callback) {
pool.getConnection((err,connection) => {
if(err) {
return callback(err, null);
} else {
if(connection) {
connection.query(sql, function (error, results, fields) {
connection.release();
if (error) {
return callback(error, null);
}
return callback(null, results);
});
}
}
});
}
function query(sql, callback) {
executeQuery(sql,function(err, data) {
if(err) {
return callback(err);
}
callback(null, data);
});
}
module.exports = {
query: query
}
Response
{"message":""}
Please change the bcrypt.compare code to following code. It is a callback function:
bcrypt.compare('123456', data.u_password, function(err, result) {
if (err) {
// Passwords don't match
message = 'Passwords dont match';
} else {
// Passwords match
message = 'Passwords match';
}
res.status(200).json({
message:message,
});
})
EDIT 1: Please update the method to following logic:
db.query(`SELECT * FROM users WHERE u_id = ${uid}`, (err, data) => {
if (err) {
throw err;
}
if (data && data.length > 0) {
var message = '';
if (data.u_password) {
bcrypt.compare('123456', data.u_password, function (err, result) {
if (err) {
// Passwords don't match
message = 'Passwords dont match';
} else {
// Passwords match
message = 'Passwords match';
}
res.status(200).json({
message: message,
});
})
}
res.status(200).json({
message: "User Not found."
});
}
res.status(200).json({
message: "User Not found."
});
});
i need to know how i can write my request to make multiple delete.
the second thing is how can i put async function on my code.
i want to delete a campus and in the same time dele the builings with the same id campus in the JSON
app.delete('/campuses/:id', (req, res)=> {
const id = req.params.id;
const details = { 'campusid': new ObjectID(id) };
db.db('').collection('buildings').remove(details, (err, result)=> {
if (err) {
res.send({ 'error': 'en error has occured' });
} else {
res.send(result);
}
});
const details2 = { '_id': new ObjectID(id) };
db.db('').collection('campuses').remove(details2, (err, result)=> {
if (err) {
res.send({ 'error': 'en error has occured' });
} else {
res.send(result);
}
}
);
})
You can delete like this.
app.delete('/campuses/:id', async (req, res)=> {
try {
const id = req.params.id;
const details = { 'campusid': new ObjectID(id) };
await db.db('').collection('buildings').remove(details);
const details2 = { '_id': new ObjectID(id) };
await db.db('').collection('campuses').remove();
res.send(result);
} catch(err) {
return res.json({
success: false,
message: 'error'
});
}
})
You could make sequential functions where the first one calls the second one. You could then pass on variables to the seconds function (ie. your campus ID).
It could look something like this:
const Query1 = (res, query) => {
const request = new sql.Request();
request.query(query, (err, result) => {
if (err) {
return res.json({
success: false,
message: 'error'
});
} else if (result.recordset[0]) {
let campusID = result.recordset;
Query2(res, campusID, query = 'SELECT bla bla')
}
})
}
const Query2 = (res, campusID, query) => {
const request = new sql.Request();
request.query(query, (err, result) => {
if (err) {
return res.json({
success: false,
message: 'error'
});
} else {
return res.json({
success: true
});
}
})
}
There are various ways to make async call.
You can use promises.
Async Functions.
Sending response without waiting for other tasks.
If you want to make parallel calls you can use bluebird join function
I like the syntax of async functions better than promises, but I use both depending on the situation.
Here is an example of running functions in order before moving to the next function:
async.waterfall([
function(callback1) {
//Do some work, then callback
if (error) {
callback1(errorGoesHere,null);
} else {
callback1(null,successMessageGoesHere);
}
},
function(callback2) {
//Do some work, then callback
if (error) {
callback2(errorGoesHere,null);
} else {
callback2(null,successMessageGoesHere);
}
}
], function (error, success) {
if (error) {
//show an error
}
//all good return the response, etc.
});
If anything in these functions fail, it automatically call the end function to catch the error.
I have a function that is inserting user credentials. I want to return value from a call back function...
var router = require('express').Router();
var User = require('../Models').users;
// function calling here
router.post('/signup', function (req, res)
{
var result = User.signUp(req.body);
res.send(result);
});
module.exports = router;
//implemetation of function
userSchema.statics.signUp = function signUp(obj) {
var user = new userModel(obj);
user.password = hash.generate(obj.password);
return user.save(function (err, newuser) {
if (err)
{
return 'Error occured during insertion..';
} else
{
return 'You have sign up successfully...';
}
});
}
I want to return the response as a string but it showing undefined. How should it be done?
var router = require('express').Router();
var User = require('../Models').users;
router.post('/signup', function (req, res)
{
var result = User.signUp(req.body, function(err, result){
if(err){
}
else{
res.send(result)
}
});
});
userSchema.statics.signUp = function signUp(obj, callabck) {
var user = new userModel(obj);
user.password = hash.generate(obj.password);
user.save(function (err, newuser) {
if (err)
{
callback( 'Error occured during insertion..');
} else
{
callback(null, newuser);
}
});
}
Use the callback i.e.
var router = require('express').Router();
var User = require('../Models').users;
// function calling here
router.post('/signup', function (req, res)
{
User.signUp(req.body,function(err,result){
res.send(result);
});
});
module.exports = router;
//implemetation of function
userSchema.statics.signUp = function signUp(obj,callback) {
var user = new userModel(obj);
user.password = hash.generate(obj.password);
return user.save(function (err, newuser) {
if (err)
{
callback('Error occured during insertion..',null);
} else
{
callback(null,'You have sign up successfully...');
}
});
}
Because of async nature .. Try this:
router.post('/signup', function (req, res)
{
var result = User.signUp(req.body, function(err, result){
if(err){}
else{res.send(result)}
});;
});
userSchema.statics.signUp = function signUp(obj, callabck) {
var user = new userModel(obj);
user.password = hash.generate(obj.password);
user.save(function (err, newuser) {
if (err)
{
callback( 'Error occured during insertion..',null);
} else
{
callback (null, 'You have sign up successfully...');
}
});
}