I have started using typescript. As part of project, I am using multer and csvtojson npm modules to upload a csv file to application and then return the data from csv file into Mongo Database.
Able to push elements to arrays members and errors i.e., confirmed by console logging the length of array, but array is returning empty in response object
//controller to import members
exports.importMembers = async (req: Request, res: Response) => {
try {
uploadFile(req, res); //Fileupload method is return in below
}
catch (error: any) {
if(error) {
return res.status(400).json({
status_code: 400,
Error: error
});
}
}
};
//method to uplaod data
const uploadFile = async (req: Request, res: Response) => {
try {
//arrays to store errors occured and members saved from file
var errors:{}[] = [], members:{}[] = [];
let filePath : string;
// multer method
upload(req, res, (err: any) => {
if(!(req.file)) {
return res.status(400).json({
status_code: 400,
Message: "Please select file to be imported!",
})
}
else if (err) {
return res.status(400).json({
status_code: 400,
Info: `Error occurred while uploading file: ${err}`,
});
}
else {
filePath = path.join("upload", req.file?.originalname);
csvtojson().fromFile(filePath).then((source: any) => {
// Fetching all data from each row and return to member object
for (var i = 0; i < source.length; i++)
{
var member = {
memberEnrollmentID: source[i]["Member Enrollment ID"],
name: source[i]["Name"],
dateOfBirth: source[i]["Date Of Birth"],
IDproofNumber: source[i]["ID Proof Number"],
email: source[i]["Email"],
phoneNumber: source[i]["Phone Number"],
address: source[i]["Address"]
};
const newMember = new Members(member); //saving member to collection
newMember.save().then((result) => {
console.log(members.length); // returning array length
members.push(result); // push saved members
}).catch((error) => {
console.log(errors.length); // returning array length
errors.push(error); // push errors occured while saving members
})
}
console.log(members.length); // returning 0
console.log(errors.length); // returning 0
return res.status(200).json({
status_code: 200,
Members_Imported : members, // returning empty array
Members_Rejected : errors // returning empty array
});
});
}
});
} catch (error: any) {
throw error; // throw an error to be handled by the calling function
}
};
How could i return the members and errors array with elements stored in a express response object?
Related
I have this request in server.js file.
app.post("/insertRowtoMain", (req, res) => {
const {nodeid, maintenancetype, personnel, process, date} = req.body;
//console.log("description",description)
let insertQuery = `insert into maintenance(nodeid,maintenancetype, personnel, process, date)
values(${nodeid},'${maintenancetype}',${personnel},'${process}', '${date}') returning id`
pool.query(insertQuery, (err, result) => {
if (!err) {
console.log("insertRowtoMain", result.rows);
res.status(200).send(result.rows);
} else {
res.status(404).json(err.message)
console.log("insertRowtoMain error", err.message)
}
})
})
And I am calling this request function in front-end with this code:
const addNewMainTypes = async () => {
try {
await axios.post(`${serverBaseUrl}/insertRowtoMain`, {
nodeid: newMaintenance.nodeid,
maintenancetype: newMaintenance.maintenancetype,
personnel: newMaintenance.personnel,
process: newMaintenance.process,
date: newMaintenance.date,
});
} catch (err) {
throw err;
}
const maintenance = await getMain();
// console.log("main list", maintenanceList);
setMaintenance(maintenance);
const maintenanceList = await getMainTypes();
// console.log("main list", maintenanceList);
setMaintenanceList(maintenanceList);
};
When I insert a new row to this function, I got the returning id in server.js terminal.
How can I use that Id in front-end?
Save the response of the POST request in a variable and access the data property
// Here, "data" will be a variable with the response data
const { data } = await axios.post(`${serverBaseUrl}/insertRowtoMain`, {
nodeid: newMaintenance.nodeid,
maintenancetype: newMaintenance.maintenancetype,
personnel: newMaintenance.personnel,
process: newMaintenance.process,
date: newMaintenance.date,
});
/* Seems like your API is returning an array of objects with "id" property, so, for example... */
// The following should console.log the first element's id of the array
console.log(data[0]?.id);
I have a cloud function that processes and stores data sent to it. Most of the data comes from the request except for some ID values I store in the main collection I am working with for reference. My problem is the data I get from the other cloud firestore collection is not persisted in the collection I am writing to. My code looks like this:
await emails.forEach(async (email: string) => {
try {
// This should only ever return one result
const student = await usersRef.where('userEmail', '==', email).get();
if (student.empty) {
console.log(`No matching documents for email: ${email}`);
} else {
student.forEach((s) => {
const studentData = s.data();
console.log('found student: ', studentData);
// StudentIds stores reference to student objects
studentIds.push(studentData.playerUniqueID);
});
}
} catch (err) {
console.log('Error finding students: ', err);
throw new functions.https.HttpsError('internal', 'Error finding students');
}
});
const sessionId = uuidv4();
const newSession: newSessionWriteRequest = {
emails, // emails is also an array of strings and is persisted properly
owner,
// StudentIds is not empty at this point and is populated correctly. StudentIds is an array of strings
studentIds,
ongoing: true,
sessionName: data.sessionName,
startTime: data.sessionStartDate,
sessionId
};
try {
// All values except studentIds are persisted to the sessionsRef except studentIds, which is a blank array
await sessionsRef.doc(sessionId).set(newSession);
console.log('new session: ', newSession);
return newSession;
} catch (err) {
console.log('Error creating new session: ', err);
throw new functions.https.HttpsError('internal', 'Error creating new session');
}
StudentIds is just an array of strings. emails is also an array of string but is stored correctly. The only difference between the two is that emails comes from the initial request to the function whereas studentIds comes from firestore. My question is why is studentIds not being persisted correctly? Is there some kind of interaction between firebase collections I am not aware of?
The issue lied with this block of code:
await emails.forEach(async (email: string) => {
try {
// This should only ever return one result
const student = await usersRef.where('userEmail', '==', email).get();
if (student.empty) {
console.log(`No matching documents for email: ${email}`);
} else {
student.forEach((s) => {
const studentData = s.data();
console.log('found student: ', studentData);
// StudentIds stores reference to student objects
studentIds.push(studentData.playerUniqueID);
});
}
} catch (err) {
console.log('Error finding students: ', err);
throw new functions.https.HttpsError('internal', 'Error finding students');
}
});
As pointed out in the comments, my await in front of the forEach loop was doing nothing. Changing it to this fixed the issue:
const studentIds: string[] = await getStudentPlayerUniqueIds(emails);
...
const getStudentPlayerUniqueIds = async(emails: string[]): Promise<string[]> => {
const studentIds: string[] = []
try {
for (const email of emails) {
const student = await usersRef.where('userEmail', '==', email).get();
if (student.empty) {
console.log(`No matching documents for email: ${email}`);
} else {
student.forEach((s) => {
const studentData = s.data();
console.log('found student: ', studentData);
studentIds.push(studentData.playerUniqueID);
});
}
}
return studentIds;
} catch (err) {
console.log('Error finding students: ', err);
throw new functions.https.HttpsError('internal', 'Error finding students');
}
}
I am just started with nodejs with react frontend. But I have some issue while authenticating user. I am trying to fetch user with specific email and password. My api for this is as follows:
I have created three files controller, services and router files for any api request.
//userServices.js
const db = require('./../../db-connection/connection')
userAuth: (params, callback) => {
db.query(`SELECT * FROM Users WHERE email = ?`,[params.email],
(error, result, fields) => {
if(!error) {
console.log('result = ' + result[0]);
return callback(error, result[0])
}
else
return callback(error)
});
}
And this is my userController js file.
//userController.js
const {create, userindex, userAuth} = require('./UserServices');
const {genSaltSync, hashSync, compareSync} = require('bcrypt');
const {sign} = require('jsonwebtoken');
userLoginAuth: (req, res) => {
const body = req.body;
userAuth(body, (error, results) => {
if (error)
console.log(error);
if (!results) {
return res.json({
success: 0,
data: 'Invalid email or password'
})
}
const result = compareSync(body.password, results.password);
if(!result) {
results.password = undefined;
const jsontoken = sign({result: results}, 'choegyel123', {
expiresIn: '1h'
});
return res.json({
success: 1,
message: 'Login successful',
token: jsontoken
})
} else
console.log('password' + result.password)
return res.json({
success: 0,
error: 'Invalid email or password'
});
});
}
But the problem is in userServices.js file. My sql query is correctly executed but in callback for the ' results ' i am getting weird object. I think I should get some array of corresponding data from the database table and in my console log I am getting [object object]. I am not sure what does this actually mean and I am also all sure this is a blocker, since I cannot retrive password with this object in my userController. Any help would be greatly appreciated. Thanks!
Issues
compareSync returns a boolean with true indicating correct password. You're using if(!result) which is the reverse.
Make sure your {} are correct on the else
You're logging result.password which is undefined because result is your compareSync return value. You meant to log results.password. Avoid using result and results for two different things because it makes it easy to make these mistakes. Something like bcryptResult and resultObj might be better.
When you console.log(), pass data as the second argument or make a second log because concatenating objects always shows [object Object].
Updated snippet
const result = compareSync(body.password, results.password);
if(result) {
results.password = undefined;
const jsontoken = sign({result: results}, 'choegyel123', {
expiresIn: '1h'
});
return res.json({
success: 1,
message: 'Login successful',
token: jsontoken
})
} else {
console.log('password', results.password)
return res.json({
success: 0,
error: 'Invalid email or password'
});
}
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();
};
I have a function that checks user input in an express application. I don't want to use any library to validate those inputs so I declared an array where errors are pushed into.
I have embedded the middleware function as a static method in a class...
static postAdchecker(req, res, next) {
let { state, price, manufacturer, model, bodytype } = req.body;
console.log('req', req.body);
const errors = [];
// If state is empty or undefined throw this error
if (!state) {
console.log('state', state);
const error = {
message: 'Please specify the state of the car'
};
errors.push(error);
}
// If state is supplied, convert it to lowercase, trim and check if value is new/used
if (state.toLowerCase().trim() !== 'new' && state.toLowerCase().trim() !== 'used') {
const error = {
message: 'State can only be new or used'
};
errors.push(error);
}
// Same goes for the others.
if (!price) {
const error = {
message: 'You will need to specify a sale price'
};
errors.push(error);
}
if (!manufacturer) {
const error = {
message: 'Specify a manufacturer'
};
errors.push(error);
}
if (!model) {
const error = {
message: 'Specify a model'
};
errors.push(error);
}
if (!bodytype) {
const error = {
message: 'You will need to specify a bodytype'
};
errors.push(error);
}
return res.status(400).json({
status: 400,
errors: {
body: errors.map(err => err.message)
}
});
console.log('errors', errors);
req.body.state = state.toLowerCase().trim();
req.body.price = price.toLowerCase().trim();
req.body.manufacturer = manufacturer.toLowerCase().trim();
req.body.model = model.toLowerCase().trim();
req.body.bodytype = bodytype.toLowerCase().trim();
// req.authData;
return next();
}
How can I achieve the following?
Convert the values in the input field to lowercase and trim when supplied.
When there are errors, return all the errors.
When there are no errors, transfer operation to the next function instead of returning an empty array.
You are just missing one condition:
if(errors.length) { // <<<
return res.status(400).json({
status: 400,
errors: {
body: errors.map(err => err.message)
}
});
}