Iterate dataArray to create an object is not happening - node.js

How can I parse the incoming nomData data array and store those values into an object along with userEmail ? Somehow below code is not working, could someone pleas advise the issue here.
Expected database columns values:
var data = { useremail: userEmail, nomineeemail: email, nomineename: name, nomineeteam: team, reason: reason }
server.js
app.post('/service/nominateperson', async (req, res) => {
try {
const userEmail = req.body.userEmail;
const nomData = req.body.nomRegister;
const formData = {
useremail: userEmail,
nomineeemail: {},
nomineename: {},
nomineeteam: {},
reason: {}
}
const newArray = nomData.map(item => {
formData.nomineeemail = item.email;
formData.nomineename = item.name;
formData.nomineeteam = item.team;
formData.reason = item.reason;
});
var data = { useremail: userEmail, nomineeemail: email, nomineename: name, nomineeteam: team, reason: reason }
// Ideally I should get nomData
//items parsed create an data object and pass that into bulkCreat() method:
const numberOfNominations = await NominationModel.count({where: {useremail: userEmail}});
if (numberOfNominations <= 3) {
const nominationData = await NominationModel.bulkCreate(data);
res.status(200).json({message: "Nomination submitted successfully !"});
} else {
res.status(202).json({message: "Nomination limit exceeded, please try next week !"});
}
} catch (e) {
res.status(500).json({fail: e.message});
}
});

So i assume nomData is an array containing multiple nominations. So if you want to bulkCreate with data you should pass an array instead of an object.
const data = nomData.map(item => ({
useremail: userEmail,
nomineeemail: item.email,
nomineename: item.name,
nomineeteam: item.team,
reason: item.reason
}));
...
await NominationModel.bulkCreate(data)

Related

Not reading data and executing a function that does not exist

So I'm building an API prototype and I have code that reads data from a Google Sheets (serving as a CMS) but the problem is when calling the route that I defined in Express.js it is not reading data from the sheet. It works for sheet 1 but not for sheet 2.
To read the data I use this package: https://www.npmjs.com/package/google-spreadsheet
Link to a copy of the Google Sheet: https://docs.google.com/spreadsheets/d/1yx0iRPPho2H1OGrvTAspkTr2b1zwzbkxeb7hRuqqNwc/edit?usp=sharing
Relevant Code:
router.get('/getallcontent', async function (req, res) {
const doc = new GoogleSpreadsheet('sheetId');
await doc.useServiceAccountAuth({
client_email: creds.client_email,
private_key: creds.private_key
});
const info = await doc.loadInfo();
const sheet = doc.sheetsByIndex[1];
const rows = await sheet.getRows()
// console.log(rows)
let contents = []
function Content(title, content, sku, author, lesson) {
this.title = title;
this.content = content;
this.sku = sku;
this.author = author;
this.lesson = lesson;
}
await rows.forEach(row => {
let content = new Content(
row._rawData[0],
row._rawData[1],
row._rawData[2],
row._rawData[3],
row._rawData[4]
)
contents.push(content)
})
res.json(Response.success(req, { content: contents }))
})
Response when calling the route:
{"request":{"result":"success","message":""},"body":{"lessons":[]}}
Expected response:
{"request":{"result":"success","message":""},"body":{"content":[{"title": "Requesting Clearance","content": "some html markup text", "sku": "requesting-clearance", "author": "John D", "lesson": "test-lesson"}]}}
Test Script does work:
async function getLessons() {
const doc = new GoogleSpreadsheet('1T8-rIN4w-T1OuYRuQ-JYI-15l9RqOXqDQ2KehWyp44E');
await doc.useServiceAccountAuth({
client_email: creds.client_email,
private_key: creds.private_key
});
const info = await doc.loadInfo();
const sheet = doc.sheetsByIndex[1];
const rows = await sheet.getRows()
rows.forEach(row => {
printContent(row)
})
}
async function printContent(rows) {
let lesson = {
title: rows._rawData[0],
content: rows._rawData[1],
sku: rows._rawData[2],
author: rows._rawData[3],
lesson: rows._rawData[4]
};
console.log(lesson)
}
Found my own answer. For some reason the contents array was being cleared after the .push and thus returned an empty array.

Express & MongoDB: Duplicate documents created at the timestamp

I am using express with MongoDB as a database and while I am sending requests using Axios library to my backend, I have found that two documents were created at the time. I figured that out by checking the createdAt field and found the two documents have the exact timestamp. I am creating createdAt & updatedAt fields using mongoose-timestamp2
Here is the code responsible for sending the documents which have isSynchronized flag set to false
const syncExams = async (token) => {
let examSyncError;
await Exam.find({ isSynchronized: false })
.cursor()
.eachAsync(async (exam) => {
// use try/catch inside the loop
// so if problem occured in one document, others will be posted normally
try {
const formData = new FormData();
formData.append("exam", JSON.stringify(exam));
Object.keys(exam.images.toJSON()).forEach((key) => {
formData.append("images", fs.createReadStream(exam.images[key]));
});
const res = await axios.post(`${BACKEND_URL}/exams/`, formData, {
maxContentLength: Infinity,
maxBodyLength: Infinity,
headers: {
...formData.getHeaders(),
Authorization: `Bearer ${token}`,
},
});
console.log(res);
exam.isSynchronized = true;
await exam.save();
} catch (err) {
examSyncError = err;
}
});
if (examSyncError) {
throw examSyncError;
}
};
And here is the controller responsible for handling the coming request and creating these documents in the database.
router.post(
"/exams",
fileUpload.array("images"),
trimmer,
syncControllers.postExam
);
const postExam = async (req, res, next) => {
let createdExam;
let exam;
let patient;
try {
const reqBody = JSON.parse(req.body.exam);
reqBody.operator = reqBody.creator;
delete reqBody._id;
delete reqBody.creator;
const { nationalID } = reqBody;
patient = await Patient.findOne({
"personalData.nationalID": nationalID,
}).exec();
if (!patient) {
return next(errorEmitter("exams.get-patient.not-found", 404));
}
createdExam = new Exam(reqBody);
// insert the new paths of the images
Object.keys(reqBody.images).forEach((key, index) => {
createdExam.images[key.replace("Path", "")].Path = req.files[index].path
.split(path.sep)
.slice(-3)
.join(path.sep);
});
createdExam.patient = patient._id;
const checkDate = new Date(createdExam.examDate);
checkDate.setMonth(checkDate.getMonth() - 3);
const nearExam = await Exam.findOne({
patient: createdExam.patient,
examDate: { $gte: checkDate, $lt: createdExam.examDate },
isGradable: true,
});
if (nearExam) {
createdExam.isGradable = false;
}
exam = await createdExam.save();
patient.exams.push(createdExam);
await patient.save();
} catch (err) {
return next(errorEmitter("exams.create.fail", 500));
}
return res.status(201).json(exam.toObject({ getters: true }));
};
I am using the following package for createdAt & updatedAt records created using this plugin.
const timestamps = require("mongoose-timestamp2");
examSchema.plugin(timestamps);
This problem occurred in two or three cases only and did not happen again until then and I could not replicate the error. I do not what caused this!
What could cause this problem to occur? Is it possible that Axios sent the same request multiple times and mongoose created two documents at the same exact time, or it could be a bug in mongoose-timestamp2 plugin?
Any help would be appreciated, thank you!

How to get the user Record using the google-cloud firestore auth by getUserByPhoneNumber?

I have to extract data from the user using auth by phone Number.
I have an array of user's phone number.
I have written a solution and it gives the required output but it doesn't terminate. How can I solve this problem?
"phoneNumberArray" is the array of user's phone number. It is mostly related to HTTP background trigger functions.I have solved this but this is a firebase issue so please see this
const user = async () => {
const getAuth = async phoneNumber => {
return auth.getUserByPhoneNumber(phoneNumber).catch(() => {
return {
phoneNumber,
uid: null,
email: '',
displayName: '',
emailVerified: false,
disabled: false,
};
});
};
const userRecord = await Promise.all(
phoneNumberArray.map(phoneNumber => {
return getAuth(phoneNumber);
}),
);
//when i console.log(userRecord) it's print the output
const x = {
'userRecord Length': userRecord.length
}
console.log(x)
return;
}
module.exports = {user}
I have used this way to solve the function.
in the main file i have to return
return x,admin;
and the calling file works like this
const {user} = require('./filename');
user().then(e => {
console.log(e.x)
e.admin.apps[0].delete();
})catch(error){
console.log(error)}

NodeJS Async/Await doesn't await (returns Promise pending)

I'm writing an API that gets past transactions on the Stellar network for a user, looks up the corresponding users in my database, and put's it all together into a JSON (to respond to the request - later).
Problem: looking up the username corresponding to the accountID ("from" field) is an async method with mongoose and only returns data after the JSON has been assembled.
I've tried to use async/await, promises, .thens but nothing seems to work.
server.payments()
.forAccount(accountId)
.cursor('now')
.order('desc')
.limit(2)
.call()
.then(function (page) {
var history = []
for(var i = 0; i<page.records.length; i++){
var obj = page.records[i]
//Get the username corresponding to the key from my database
//FIXME
var username
findUser(obj["from"]).then(result => {
username = result
})
var payment = {
"currency":obj["asset_code"],
"from": obj["from"],
"username":username,
"amount": obj["amount"],
"timestamp":obj["created_at"]
}
history.push(payment)
}
console.log(history)
//console.log(JSON.stringify(history))
})
.catch((err) => {
console.log(err)
})
async function findUser(senderKey){
var user = await mongoose.User.findOne({publicKey: senderKey})
console.log(user.username)
return user.username
}
Expected result: findUser returns value, payment variable uses it and gets logged together.
What happens: findUser starts looking for data, payment variable gets put together (username as undefined) and logged, findUser returns data.
Here's the log: (spiderman is the actual username from my database)
[ { currency: 'MEUR',
from: 'GACRQARPR2OMWRG6IH7HM5DYTA3FMM6UKA7NKS4BIJIADRIKFRPAIE7G',
username: undefined,
amount: '3.0000000',
timestamp: '2019-05-07T13:37:04Z' },
{ currency: 'MEUR',
from: 'GACRQARPR2OMWRG6IH7HM5DYTA3FMM6UKA7NKS4BIJIADRIKFRPAIE7G',
username: undefined,
amount: '2.0000000',
timestamp: '2019-05-07T13:34:21Z' } ]
spiderman
spiderman
Highlight recommend, you can make it easy with async/await syntax for your case.
You will wait until the server responses the page, then each of obj in page.records (.map or .forEach... will make you some mess), you wait for findUser function returns the username, then do your business.
try {
const page = await server.payments()
.forAccount(accountId)
.cursor('now')
.order('desc')
.limit(2)
.call()
const history = [];
for (const obj of page.records) {
const username = await findUser(obj["from"]);
const payment = {
"currency": obj["asset_code"],
"from": obj["from"],
"username": username,
"amount": obj["amount"],
"timestamp": obj["created_at"]
}
history.push(payment)
}
console.log(history)
} catch (e) {
console.log(e)
}
Remind: await expression only allowed within an async function.
You can use the new "for of" loop along with async await :-
server.payments()
.forAccount(accountId)
.cursor('now')
.order('desc')
.limit(2)
.call()
.then(async function (page) {
var history = []
for(const obj of page.records) {
const username = await findUser(obj["from"]);
var payment = {
"currency":obj["asset_code"],
"from": obj["from"],
"username":username,
"amount": obj["amount"],
"timestamp":obj["created_at"]
}
history.push(payment)
}
console.log(history)
//console.log(JSON.stringify(history))
})
.catch((err) => {
console.log(err)
})
You need a conditional that checks whether the function you are awaiting has completed
async function findUser(senderKey){
var user = await mongoose.User.findOne({publicKey: senderKey})
if (user){
console.log(user.username)
return user.username
}
}

Sequelize Transaction inside forEach loop

I'm trying to use transaction inside forEach loop using async/await syntax of Node 7.0+
When I try to print committed transaction response in console, I'm able to see the values but those same values are not committed in to DB.
Below is the code :
documentInfo.forEach(async (doc) => { // array of documentInfo
var frontImgName = await module.exports.uploadImage(docFiles, doc.front, req, res )
var backImgName = await module.exports.uploadImage(docFiles, doc.back, req, res )
var checkKycDoc = await KYCDocument.findOne({
where: {
kyc_id: checkUserKyc.dataValues.kyc_id,
user_id: checkUserKyc.dataValues.user_id
}
})
if (checkKycDoc) { //update
var updateDocument = await KYCDocument.update({
document_name: doc.document_name,
front_image: frontImgName,
back_image: backImgName
}, {
where: {
kyc_id: checkUserKyc.dataValues.kyc_id,
user_id: checkUserKyc.dataValues.user_id
},
}, {transaction})
log('updateDocument', updateDocument.dataValues)
} else { // insert
var newKycDocument = await new KYCDocument({
kyc_id: checkUserKyc.dataValues.kyc_id,
user_id: checkUserKyc.dataValues.user_id,
document_name: doc.document_name,
front_image: frontImgName,
back_image: backImgName,
status: true
}, {transaction})
log('newKycDocument', newKycDocument.dataValues)
}
if (rowCount === documentInfo.length) {
await transaction.commit() // transaction is printed on this line
log('KYC has been uploaded successfully')
helpers.createResponse(res, constants.SUCCESS,
messages.KYC_UPLOAD_SUCCESS,
{'error': messages.KYC_UPLOAD_SUCCESS}
)
} else {
rowCount++
}
})
The issue was in the create method.
To resolve the issue I had to create a new row using:
var newKycDocument = await KYCDocument.create({
kyc_id: checkUserKyc.dataValues.kyc_id,
user_id: checkUserKyc.dataValues.user_id,
document_name: doc.document_name,
front_image: frontImgName,
back_image: backImgName
}, {transaction})
I was missing the .create method.

Resources