How do I update an array inside different function in NodeJS? - javascript

I want to update ans object inside the fetchAll() functions and then send it back after successful updation. But the response I get is '[]'.
var ans = []
Country.fetchAll(newdate,(err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while retrieving data."
});
else ans.push(data);
});
State.fetchAll(newdate2,(err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while retrieving data."
});
else ans.push(data);
});
res.send({ status: 201, data: ans });
How do I update the ans array inside the functions?

You can convert callback to Promise and using async/await to control the flow. async/await is supported in Node.js 7.6
const getCountry = (date) =>
new Promise((resolve, reject) => {
Country.fetchAll(date, (err, data) => {
if (err) {
reject(
new Error(err.message || "Some error occurred while retrieving data.")
);
return;
}
resolve(data);
});
});
const getState = (date) =>
new Promise((resolve, reject) => {
State.fetchAll(date, (err, data) => {
if (err) {
reject(
new Error(err.message || "Some error occurred while retrieving data.")
);
return;
}
resolve(data);
});
});
const foo = async (res) => {
try {
const [country, state] = await Promise.all([
getCountry(newdate),
getState(newdate2),
]);
const ans = [country, state];
res.send({ status: 201, data: ans });
} catch (err) {
res.status(500).send({ message: err.message });
}
};
Node.js v8 added util function to promisify the callback, the code can be simplified to
const util = require('util');
const foo = async (res) => {
try {
const getCountry = util.promisify(Country.fetchAll);
const getState = util.promisify(State.fetchAll);
const [country, state] = await Promise.all([
getCountry(newdate),
getState(newdate2),
]);
const ans = [country, state];
res.send({ status: 201, data: ans });
} catch (err) {
res.status(500).send({ message: err.message || "Some error occurred while retrieving data." });
}
};

Related

return value remains undefined even when timed out for 10 seconds

I had an issue where I needed to return the response of an async function which kept being returned as undefined. So I decided to use setTimeout() before trying to use it. It still doesn't seem to work. Can someone explain why?
My attempt:
insertUser = (req,res) => {
var record = {
'handle': req.body.handle,
'name': req.body.name,
'password': req.body.password
};
var response;
createUser(record, response)
setTimeout(() => {
console.log(response);
},10000)
};
createUser = (record, response) => {
users.insertOne(record, function(err, result){
if(err){
response = {'code': 404, 'message': 'Something went wrong. Message: ', err}
}else{
response = {'code': 200, 'message': result.insertedId}
}
})
setTimeout(() => {
console.log(response)
}, 1000);
};
The problem is that users.insertOne doesn't run synchronously, and the function createUser returns before that, hence you are getting undefined as a return value.
There are a couple of ways you can solve this -
=> Using async/await
const createUser = async (record, response) => {
try {
const result = await users.insertOne(record);
response = {
'code': 200,
'message': result.insertedId
}
} catch (err) {
response = {
'code': 404,
'message': 'Something went wrong. Message: ',
err
}
})
return response;
};
const insertUser = async (req,res) => {
let record = {
'handle': req.body.handle,
'name': req.body.name,
'password': req.body.password
};
let response;
response = await createUser(record, response);
console.log(response);
};
=> Using plain promises
const createUser = (record) => {
return new Promise((resolve, reject) => {
users.insertOne(record, function(err, result) {
if (err) {
// Or use `reject` if you want to have this in .catch callback
resolve({
'code': 404,
'message': 'Something went wrong. Message: ',
err
});
} else {
resolve({
'code': 200,
'message': result.insertedId
});
}
})
})
};
const insertUser = (req, res) => {
const record = {
'handle': req.body.handle,
'name': req.body.name,
'password': req.body.password
};
let response;
createUser(record).then((res) => {
response = res;
console.log(response);
});
};

Should i use promise or callback in the following code?

I have some routes
routes.js
var express = require("express");
var router = express.Router();
const { controllerMethod1, controllerMethod2 } = require("./controller");
router.get("/route1", controllerMethod1);
router.get("/route2", controllerMethod2);
module.exports = router;
if i use promise variable as global,
its used by all method in controller.js.
should i use global or local variable for promise ?
controller.js
const {
serviceMethod1,
serviceMethod2,
serviceMethod1ByDate,
} = require("./services");
let promise; //global promise variable
const controllerMethod1 = (req, res) => {
//let promise; local promise variable
//This is for Callback
if (req.query.date) {
serviceMethod1ByDate(req.query.date, (err, result) => {
if (err) {
res.status(500).json({
status: "error",
message: "error using callback",
});
}
if (result) {
res.status(200).json({
status: "success",
message: "success using callback",
});
}
});
} else {
serviceMethod1((err, result) => {
if (err) {
res.status(500).json({
status: "error",
message: "error using callback",
});
}
if (result) {
res.status(200).json({
status: "success",
message: "success using callback",
});
}
});
}
// This is for Promise
promise = req.query.date
? serviceMethod1ByDate(req.query.date)
: serviceMethod1();
Should i use way 1 or way 2 ?
if multiple users request one or more routes at the same time,can handleResponse method work correctly?
Way 1 for promise
promise
.then((results) => {
return res.json({
status: "success with promise variable",
data: results,
});
})
.catch((error) => {
return res.status(500).json({
status: "error with promise variable",
message: "there is no person details",
});
});
Way 2 for Promise
handleResponse(promise, res);
//this method is working for all routes when i use promise
const handleResponse = (results, response) => {
results
.then((result) => {
return response.json({
status: "success with promise variable in handleResponse",
data: result,
});
})
.catch((error) => {
return response.status(500).json({
status: "error with promise variable handleResponse",
message: "Internal Server Error",
});
});
};
controller.js
const controllerMethod2 = (req, res) => {
//------------------ Using Callback Method -------------
serviceMethod2((err, result) => {
if (err) {
res.status(500).json({
status: "error",
message: "error using callback",
});
}
if (result) {
res.status(200).json({
status: "success",
message: "success using callback",
});
}
});
//------------------ Using Promise Method -------------
//local variable
let promise;
promise = serviceMethod2();
//Way 1 for Promise
promise
.then((result) => {
//...
})
.catch((err) => {
//...
});
//Way 2 for Promise
handleResponse(promise, res);
};
module.exports = { controllerMethod1, controllerMethod2 };
service.js
const pool = require("../../../config/database");
//-----------------------Using Callback Mehthod----------------
const serviceMethod1 = async (CallBack) => {
let query = "select * from databse";
await pool.query(query, [], (error, results, fields) => {
if (error) {
return CallBack(error);
}
return CallBack(null, results);
});
};
const serviceMethod1ByDate = async (date) => {
let query = "select * from databse where date ?";
return await new Promise((resolve, reject) => {
pool.query(query, [date], (error, results, fields) => {
if (error) {
return CallBack(error);
}
return CallBack(null, results);
});
});
};
const serviceMethod2 = async (Callback) => {
let query = "select * from database";
await pool.query(query, [], (error, results, fields) => {
if (error) {
return CallBack(error);
}
return CallBack(null, results);
});
};
//-----------------------Using Promise Method----------------
const serviceMethod1 = async () => {
let query = "select * from databse";
return await new Promise((resolve, reject) => {
pool.query(query, [], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
const serviceMethod1ByDate = async (date) => {
let query = "select * from databse where date ?";
return await new Promise((resolve, reject) => {
pool.query(query, [date], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
const serviceMethod2 = async () => {
let query = "select * from database";
return await new Promise((resolve, reject) => {
pool.query(query, [], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
module.exports = {
serviceMethod1,
serviceMethod1ByDate,
serviceMethod2,
};
if i use promise variable as global, its used by all method in controller.js. should i use global or local variable for promise ?
You should use local variable for this type of operation as global variable are generally used to define constants or methods. They cannot be used as temporary values because it's value can be changed anytime and that'll result in conflict with other functionalities and so must be avoided.
Should i use way 1 or way 2 ? if multiple users request one or more routes at the same time,can handleResponse method work correctly?
Way 2 is more efficient that Way 1 because if you use way 1 then you will have to do it for every method in the controller. Way 2 is like a common method where you can format your response and most of the developers use it.
It doesn't make any difference whether you use callbacks or promises but just a clean way to do things.
Instead of using this:
const serviceMethod1 = async () => {
let query = "select * from databse";
return await new Promise((resolve, reject) => {
pool.query(query, [], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
Use this:
// Remove the async await from here and handle the response/error where the below method is called by putting it in try catch block.
const serviceMethod1 = () => {
let query = "select * from databse";
return new Promise((resolve, reject) => {
pool.query(query, [], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
// otherFile.js
someMethod = async () => {
try {
const result = await serviceMethod1();
// handle the response
} catch {
// handle the error
}
}

How to work with Async/Await in expressjs router?

I've been battling with an issue concerning Async/Await, I'm relatively new to Nodejs. I have a repository where I connect directly to my mongodb collection to retrieve some data it but when I connect my controller to this repository, I get a nulled response.
Please checkout my code below:-
SyncRepository.js
const mongoose = require('mongoose');
exports.ItemRepo = async (limit) => {
try {
await mongoose.connection.db.collection('items_1087342')
.find({}, {timeout: false}).limit(limit).toArray((err, results) => {
// results.forEach(e => {
// console.log(e.item_id);
// }); //This works well
return results;
});
} catch (e) {
throw Error('Error Loading Data:- ' + e.message);
}
};
SyncController.js
const syncRepo = require('../../../Repositories/Sync/SyncRepository');
exports.getItem = async (req, res) => {
try {
await syncRepo.ItemRepo(7)
.then(element => {
console.log(element);
return res.json(element); //This return null
});
// return await res.json(await syncRepo.ItemRepo(7));
} catch (e) {
return res.status(400).json({ status: 400, message: e.message });
}
};
You are mixing async/await and traditional Promise syntax. Try this :
SyncRepository.js
const mongoose = require('mongoose');
exports.ItemRepo = limit => {
return mongoose.connection.db.collection('items_1087342')
.find({}, {timeout: false})
.limit(limit)
.exec() // see #Enslev's explanation in the comments
};
SyncController.js
const syncRepo = require('../../../Repositories/Sync/SyncRepository');
exports.getItem = async (req, res) => {
try {
let element = await syncRepo.ItemRepo(7)
return res.json(element);
} catch (e) {
return res.status(400).json({ status: 400, message: e.message });
}
};

Make query for every object in json using for or forEach

My problem is, I want to make INSERT query for every object from JSON using some loop, but I almost always got an error "Cannot set headers after they are sent to the client".Can someone help?Tnx
const connection = require('./config');
module.exports.excel = function (req, res) {
var _query = 'INSERT INTO excel (id, first_name, last_name) values ?';
var jsonData = req.body;
var values = [];
function database() {
return new Promise((resolve, reject) => {
jsonData.forEach((value) => {
values.push([value.id, value.first_name, value.last_name]);
connection.query(_query, [values], (error, results) => {
if (error) {
reject(
res.json({
status: false,
message: error.message
}))
} else {
resolve(
res.json({
status: true,
data: results,
message: 'Excel file successfully created in database'
}))
}
});
});
})
}
async function write() {
await database();
}
write();
}
After I got JSON from my Angular 6 front I put req.body into jsonData and try with forEach to put every object("value" in this case) into query and write that into Excel file.
You will have to wrap each query in a Promise and wait for all to complete before sending the response using Promise.all
Not that database() is going to throw when one of the queries fail and you won't have any access to the resolved promises.
const connection = require('./config');
module.exports.excel = function(req, res) {
const _query = 'INSERT INTO excel (id, first_name, last_name) values ?';
const jsonData = req.body;
function database() {
return Promise.all(
jsonData.map(
value =>
new Promise((resolve, reject) => {
const values = [value.id, value.first_name, value.last_name]
connection.query(_query, [values], (error, results) => {
if (error) {
reject(error.message);
return;
}
resolve(results);
});
})
)
);
}
async function write() {
try {
const results = await database();
res.json({
status: true,
data: results,
message: 'Excel file successfully created in database'
});
} catch (e) {
res.json({
status: false,
message: e.message
});
}
}
write();
};

Structure of multiple nested Mongoose promises

How would I structure a function that has multiple Mongoose.findOne() nested in each other?
I need to do something like
const userId = '...';
const postId = '...';
const imageId = '...';
User.findById(userId).then(user => {
if (!user) {
return res.status(400).json({
status: 'error',
err: 'User not found',
});
}
Post.findById(postId).then(post => {
if (!post) {
return res.status(400).json({
status: 'error',
err: 'Post not found',
});
}
Image.findById(imageId).then(image => {
if (!image) {
return res.status(400).json({
status: 'error',
err: 'Image not found',
});
// DO SOMETHING WITH VARIABLES 'user', 'post', AND 'image'
}).catch(err => { .. });
}).catch(err => { .. });
}).catch(err => { .. });
Since Collection.findById() returns a promise, I guess I should use chaining instead of this structure.
So it might be something like
User
.findById(userId)
.then(user => Post.findById(postId))
.then(post => Image.findById(imageId))
.then(image => {
// DO SOMETHING WITH VARIABLES 'user', 'post', AND 'image'
});
.catch(err => { .. });
but I don't know how to access the variables user, post, and image, and how to throw the errors, so I can access them in my catch statement.
Edit
I have tried this
async function getPostAsync() {
const userId = '597989c668189f31483ffdbf';
const postId = '597989c62624ea74750c74f8';
if (!userId) {
throw new Error('User id missing');
}
if (!postId) {
throw new Error('Post id missing');
}
const user = await User.findById(userId);
const post = await Post.findById(postId);
return post;
}
app.get('/', (req, res) => {
getPostAsync().then(post => {
res.json({
status: 'success',
});
}).catch(err => {
res.status(400).json({
status: 'error',
err
});
})
});
but I just receive
{
"status": "error",
"err": {}
}
Am I doing something wrong?
But I get the same result even with
async function getPostAsync() {
throw new Error('msg');
return Post.find();
}
so I might be calling the async function wrong.
You can use Promise.all:
Promise.all([
User.findById(userId),
Post.findById(postId),
Image.findById(imageId)
])
.then(result)=>{
let user = result[0];
let post = result[1];
let image = result[2];
})
.catch(err => { .. });
Or with destructing assignment:
Promise.all([
User.findById(userId),
Post.findById(postId),
Image.findById(imageId)
])
.then(([user, post, image])=>{...})
.catch(err => { .. });
You can't access those variables inside a later promise's then, but you can get round it by assigning the local resolved values to global variables
let globalUser, globalPost; // create variables for later
User
.findById(userId)
.then(user => {
globalUser = user; // assign to global
return Post.findById(postId)
})
.then(post => {
globalPost = post; // assign to global
return Image.findById(imageId)
})
.then(image => {
// DO SOMETHING WITH VARIABLES 'globalUser', 'globalPost', AND 'image'
})
.catch(err => {... });
EDIT: or when using async/await:
async function() {
const user = await User.findById(userId);
const post = await Post.findById(postId);
const image = await Image.findById(imageId);
// do something with user, post and image
}
Seeing as your promises don't rely on each other you could also use Promise.all() in an async function:
async function() {
const result = await Promise.all([
User.findById(userId),
Post.findById(postId),
Image.findById(imageId)
]);
const [user, post, image] = result;
// do something with user, post and image
}
EDIT 2: Error handling
async function getImage() {
let user;
try {
user = await User.findById(userId);
} catch (error) { // deal with rejection of `User.findById`
// do something with error
}
// if these fail the entire function will throw
const post = await Post.findById(postId);
const image = await Image.findById(imageId);
return image;
}
getImage()
.then(image => {... })
.catch(error => {... }); // deal with rejection of `getImage` as a whole
The above code showcases the ways you can handle errors in an async function. The first is how we deal with an error in the User.findById function, by simply wrapping it in a try catch block.
The second method is by simply letting the entire async function throw an error. I.e. if the Post.findById or Image.findById promises reject, the entire getImage() promise will reject, which you can deal with in the .catch() handler.

Categories

Resources