Query was already executed: User.find({}), why iam getting this error? - node.js

**
filtersRouter.js:-
filtersRouter.get('/search', getEmployeesByKey)
filterController.js
//?find employees by search key
export const getEmployeesByKey = async (req, res, next) => {
try {
const filters = req.query;
// filters.clone();
// const expr= req.query. expr;
// const {location, role} = req.query
const filterdusers = await User.find(user =>{
let isValid = true;
for(let key in filters){
console.log(key, user[key], filters[key]);
isValid = isValid && user[key] == filters[key]
}
return isValid;
});
if (!employees) {
return res_failed(res, "Employees are not found");
}
res_success(res, "search done", filterdusers);
console.log(res.query);
res.status(200).json(
{filterdusers}
)
}catch(error){
res_catch(res, error);
}
};
**search the employees by giving the values dynamically like "location":"hyderabad", "skills":"nodeJS" like this.
if i give the values like "location: Hyderabd", "skills:nodeJS", it should have to print the details of employees according to given input.

Related

Unable to map inside an async function

In the below code, I am fetching data from an external api. After parsing the data as json, I wanted to map through it and get a modified version.
For some reason, the console.log(jsonData) inside the map function is not getting executed. Please check the code below for clarity
const getRandomOutfit = async (req, res) => {
const { gender, countryCode } = req.params;
if (req.params.gender === "FEMALE" || req.params.gender === "MALE") {
try {
const response = await fetch(URL);
const jsonData = await response.json();
const outputData = jsonData.map((productItem) => {
console.log(productItem); // doesn't get printed
// some operation
return productItem;
});
await res.json(jsonData);
} catch (error) {
res.status(500).send("Error getting data");
}
} else {
res.status(500).send("Invalid category");
}
};
I'm confused about what I am missing here and making an error.
I rewrote the code to make it clearer to understand. In general, it is best to take the fail first approach. Notice, how the first thing I do is return upon failure.
As to why you code is not printing anything out, try printing jsonData. It might be that this is an empty array.
const getRandomOutfit = async (req, res) => {
const { gender, countryCode } = req.params;
if (gender !== "FEMALE" && gender !== "MALE")
return res.status(500).send("Invalid category");
try {
const response = await fetch(URL);
const jsonData = await response.json();
console.log(jsonData); // what does this return?
const outputData = jsonData.map((productItem) => {
console.log(productItem); // doesn't get printed
// some operation
return productItem;
});
await res.json(jsonData);
} catch (error) {
res.status(500).send("Error getting data");
};

How to return data in an async function in node.js? My code return [object Promise] but I want the response.length

I want the array length, but the function returns [object Promise]. I send a correct email and I just need know if it's already in collection.
const res = require('express/lib/response');
async function emailUnique(email){
var query = { email: email };
const response = await dbo.collection('users').find(query).toArray();
const tot = response.length;
return tot;
}
const emailValidate = function (email) {
if (email.indexOf('#') === -1 || email.indexOf('.') < 0) {
message = 'Invalid entries. Try again.';
}else{
let quantos = emailUnique(email);
message = quantos;
}
return message;
};
module.exports = emailValidate;
Thanks, Its a simplified answer:
emailValidate.mod.js
const res = require('express/lib/response');
function emailValidate(email) {
return new Promise((resolve) => { // return a promise
var query = { email: email };
dbo.collection('users').find(query).toArray((_err, result) => {
resolve(result.length); //the returned value
});
});
}
module.exports = emailValidate;
user.js
const mod_emailValidate = require('./emailValidate.mod');
exports.getUsers = (req, res) => {
const { name } = req.body;
const { email } = req.body;
const { password } = req.body;
async function run() { // make an async function
let data = await mod_emailValidate(email); //call the function with await
console.log(`Retornou: ${data}`);
}
run();
res.status(400).send({ message: 'Fired' });
};

Promise.all and .map returning null

const returnPostData = async (req, res, initialPostsQueryArray) => {
const promises = initialPostsQueryArray.map((post) => {
let postObject;
voteCount = sumValues(post.voting_options);
pool.query('SELECT voting_option FROM votes WHERE user_id = $1 AND post_id = $2',
[req.user.userId, post.post_id],
(error, results) => {
if (error) {
console.log(error);
return res.json({'Error': error.detail});
}
userVoteOption = results.rows[0].voting_option;
});
postObject.voteCount = voteCount;
postObject.userVoteOption = userVoteOption;
return postObject;
});
return Promise.all(promises).then(postData => {
return res.json(postData);
})
}
I'm trying to return an array of the postObjects for each post. For some reason it keeps on printing null for these objects because the return res.json is somehow running before the promises are even done. Any help is appreciated.
I had this problem before and used the same code, but it didn't work for this one for some reason.
Multiple problems:
You return postObject before userVoteOption is assigned
You don't actually use promises with node-postgres
…and therefore the return value of the map callback is not a promise
You never initialse postObject
You marked your function as async but never use await
You handle each error in the loop individually (which leads to res.json being called multiple times in case of multiple errors)
To fix these, use
async function returnPostData(req, res, initialPostsQueryArray) {
try {
const promises = initialPostsQueryArray.map(async (post) => {
const voteCount = sumValues(post.voting_options);
const results = await pool.query(
'SELECT voting_option FROM votes WHERE user_id = $1 AND post_id = $2',
[req.user.userId, post.post_id]
);
const userVoteOption = results.rows[0].voting_option;
const postObject = { voteCount, userVoteOption };
return postObject;
});
const postData = await Promise.all(promises);
res.json(postData);
} catch(error) {
console.log(error);
res.json({'Error': error.detail});
}
}
In addition, you actually shouldn't use a loop at all here. Just query multiple rows from postgres at once! Using this approach to supply the ids:
async function returnPostData(req, res, initialPostsQueryArray) {
try {
const voteCounts = new Map();
const ids = [];
for (const post of initialPostsQueryArray) {
ids.push(post.post_id);
voteCounts.set(post.post_id, sumValues(post.voting_options));
}
const {rows} = await pool.query(
'SELECT post_id, voting_option FROM votes WHERE user_id = $1 AND post_id = ANY($2::int[])',
[req.user.userId, ids]
);
const postData = rows.map(row => {
const postObject = {
voteCount: voteCounts.get(row.post_id),
userVoteOption: row.voting_option,
};
return postObject;
});
const postData = await Promise.all(promises);
res.json(postData);
} catch(error) {
console.log(error);
res.json({'Error': error.detail});
}
}

pass mysql value from node js to angular

Hi i have this post function to call create function which will insert to database
router.post('/', async (req, res, next) =>
{
const body = req.body;
console.log("tu sam todo_task",req.body);
try
{
const todo_task = await TodoTaskService.create(body);
console.log(todo_task, "function")
// created the todo_task!
return res.status(201).json({ todo_task: todo_task });
}
catch(err)
{
}
});
Then in second snippet i have this create function in service class where i want to return result from mysql query
class TodoTaskService
{
static create(data)
{
console.log("tu sam service todo_task create");
var vres = todoTaskValidator.validate(data, todo_taskVSchema);
/* validation failed */
if(!(vres === true))
{
let errors = {}, item;
for(const index in vres)
{
item = vres[index];
errors[item.field] = item.message;
}
throw {
name: "ValidationError",
message: errors
};
}
console.log("tu sam service todo_task validation passed");
let todo_task = new TodoTaskModel(data.todo_task_name, data.todo_task_complete_f);
let connection = mysql.createConnection(dev);
// insert statment
let sql = `INSERT INTO todo_task (todo_task_name,todo_task_complete_f) VALUES (?);`
let values = [data.todo_task_name, data.todo_task_complete_f];
// execute the insert statment
connection.query(sql, [values], (err, results, fields) => {
if (err) {
global.query = "Database error";
console.log(err.message + "zasto");
return err
}
else{
// get inserted rows
global.query = "OK";
todo_task.todo_task_id = results.insertId
console.log("rows inserted",todo_task);
return todo_task;
}
});
}
}
How can i pass return todo_task from connection.query back to the first post function and send it to angular?
I've found a solution on my own, don't know how if it's the best practice but here is my solution, I'm using callback to pass the value
router.post('/', async (req, res, next) =>
{
const body = req.body;
try
{
return await TodoTaskService.create(body,function (result){
console.log(result, "function result")
todo_task = result;
return res.status(201).json({ todo_task: todo_task });
});
// created the todo_task!
//return res.status(201).json({ todo_task: todo_task });
}
returning callback with result
class TodoTaskService
{
static create(data,callback)
{
var vres = todoTaskValidator.validate(data, todo_taskVSchema);
/* validation failed */
if(!(vres === true))
{
let errors = {}, item;
for(const index in vres)
{
item = vres[index];
errors[item.field] = item.message;
}
throw {
name: "ValidationError",
message: errors
};
}
console.log("tu sam service todo_task validation passed");
let todo_task = new TodoTaskModel(data.todo_task_name, data.todo_task_complete_f);
/* todo_task.uid = 'c' + counter++;
todo_tasks[todo_task.uid] = todo_task; */
let connection = mysql.createConnection(dev);
// insert statment
let sql = `INSERT INTO todo_task (todo_task_name,todo_task_complete_f) VALUES (?);`
let values = [data.todo_task_name, data.todo_task_complete_f];
// execute the insert statment
connection.query(sql, [values], (err, results, fields) => {
if (err) {
global.query = "Database error";
console.log(err.message + "zasto");
return err
}
else{
// get inserted rows
global.query = "OK";
todo_task.todo_task_id = results.insertId
console.log("rows inserted",todo_task);
return callback(todo_task);
}
});
}

Express + Mongoose: async/await returning undefined

I'm trying to separate route code from database codes, but I'm stuck with an error when the route make an call to controller method.
I have the productRoutes.js:
router.route('/')
.get(async (req, res, next) => {
try {
let criteria = {};
for (const el in req.query) {
criteria[el] = req.query[el];
}
console.log('Getting all products', criteria);
const result = await controller.getAll(criteria);
console.log('router result:', result);
const status = (result.ok ? (result.count > 0 ? 200 : 404 ) : 400);
return res.status(status).send(result);
} catch (err) {
return next(err);
}
});
The productController.js:
exports.getAll = (criteria) => {
model.find(criteria, '-__v').exec((err, records) => {
const ok = (err ? false : true);
let result = {}
result.ok = ok;
if (ok) {
result.data = records;
result.count = records.length;
} else {
result.count = 0;
result.err = err;
}
console.log('controller result count:', result.count);
return result;
});
}
When executed it produces this:
Getting all products {}
router result: undefined
TypeError: Cannot read property 'ok' of undefined
at router.route.post.get (C:\dev\projects\mercante\server\routes\productRoutes.js:58:36)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
controller result count: 4
The execution isn't waiting for controller.getAll(criteria).
I've tried some codes I found looking for similar questions, like try/catch the async call, but didn't works or I missed some detail.
Thanks in advance.
The reason: Your controller's getAll method doesn't return any value.
You should do smth like this:
exports.getAll = async (criteria) => {
// Return value!
return await model.find(criteria, '-__v');
}
Thanks, #Rashad. Now it works:
productController.js:
exports.getAll = async (criteria) => {
return await model.find(criteria, '-__v');
}
productRoutes.js:
.get(async (req, res, next) => {
try {
let criteria = {};
for (const el in req.query) {
criteria[el] = req.query[el];
}
console.log('Getting all products', criteria);
let result = {};
const data = await controller.getAll(criteria);
result.count = data.length;
result.data = data;
const status = (result.ok ? (result.count > 0 ? 200 : 404 ) : 400);
return res.status(status).send(result);
} catch (err) {
return next(err);
}
});

Resources