Why mongoose is not awaiting for await new MODEL.save() - javascript

I have 2 servers and one of these is work fine, but second (modified variant of first) is not
`This is not works:
router.post("/", async (req, res, next) => {
const newBriefAppeal = await new BriefAppeal(req.body);
let appealId;
let target;
let goals;
let brand;
let ***;
try {
const savedBriefAppeal = await newBriefAppeal.save(function (err, appeal) {
appealId = appeal.id;
target = appeal.step01target;
goals = appeal.step02goals;
brand = appeal.step03brand;
*** = appeal.***
});
res.status(200).json(savedBriefAppeal);
} catch (err) {
res.status(500).json(err);
}
});
`
and i got error
node:events:491
throw er; // Unhandled 'error' event
^
TypeError: Cannot read properties of undefined (reading 'id')
`but this variant in my similar project works fine:
router.post("/", async (req, res, next) => {
const newAppeal = await new Appeal(req.body);
let appealId;
let name;
let email;
let phone;
let subject;
let message;
let attachments = [];
try {
const savedAppeal = await newAppeal.save(function (err, appeal) {
appealId = appeal.id;
name = appeal.name;
email = appeal.email;
phone = appeal.phone;
subject = appeal.subject;
message = appeal.text;
attachments = appeal.appealAttach.map((attachment) => ({
filename: attachment,
path: "./uploads/media/mailAttachments/" + attachment,
}));
});
res.status(200).json(savedAppeal);
} catch (err) {
res.status(500).json(err);
}
});
Where's i'm wrong and why my appeal is undefined ?

Because you're passing in a callback. As it says in the documentation, save only returns a promise when you don't pass in a callback:
Returns:
...Returns undefined if used with callback or a Promise otherwise.
Either use the old-style callback signature or use the promise feature.

Related

Why is Data not being passed through my Node REST API?

I have the following code.
routes/index.js:
const express = require('express');
const router = express.Router();
const weeklyReportsController = require('../controllers/weeklyReportsController');
router.get('/weekly_reports', weeklyReportsController);
module.exports = router;
controllers/weeklyReportsController.js:
const weeklyReportsService = require('../services/weeklyReportsService');
const weeklyReportsController = async (req, res) => {
try {
const data = await weeklyReportsService;
res.json({data})
console.log('Weekly reports controller - success');
} catch(err) {
console.log(err);
}
};
module.exports = weeklyReportsController;
services/weeklyReportsService.js:
const Pool = require('pg').Pool
const pool = new Pool({connection data})
const weeklyReportsService = async () => {
const res = await pool.query('SELECT * FROM reports', (err, results) => {
if (err) {
throw err;
} else {
console.log('Weekly reports service - success.');
}
return res.status(200).json(results.rows);
});
};
module.exports = weeklyReportsService;
All I am returning by visiting localhost:8080/api/weekly_reports is an empty JSON object of {}. I tried adding some console.log() methods to my code to see what was triggering and what wasn't, and the log from my service is not being set off. I have spent a couple hours trying to dig through example codes, reading documentation, and honestly just looking blankly at my screen - I just can't figure out what I did wrong here.
Does anyone have a suggestion as to what I am doing wrong here?
Thank you all for your time and if there is anything I can add for clarity, please don't hesitate to ask and I will provide it.
Thank you for your help.
EDIT: The data is sitting in a Postgres database called reports with the table also called reports.
There are many things wrong with your approach
Here's how you can achieve what you're trying to do:
controllers/weeklyReportsController.js:
const weeklyReportsController = async (req, res) => {
try {
const data = await weeklyReportsService();
res.status(200).json({data})
console.log('Weekly reports controller - success');
} catch(err) {
console.log(err);
res.status(500).json({error: err.message})
}
};
module.exports = weeklyReportsController;
services/weeklyReportsService.js:
const Pool = require('pg').Pool
const pool = new Pool({connection data})
const weeklyReportsService = () => {
return new Promise((resolve,reject) => {
pool.query('SELECT * FROM reports', (err, results) => {
if (err) reject(err);
console.log('Weekly reports service - success.');
resolve(results.rows)
});
})
};
module.exports = weeklyReportsService;
some links to help you get started:
https://expressjs.com/en/api.html#res
https://developer.mozilla.org/en-US/docs/Glossary/Callback_function
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://stackoverflow.com/a/64052334/2703813
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

create middlware with input argument in nodejs

i want to create a misslware in nodejs for access Level , i create this middlware :
class AccessUser extends middlware {
async AccessUser(access,req, res, next) {
const getTokenFrom = (req) => {
const authorization = req.headers["authorization"];
if (authorization && authorization.toLowerCase().startsWith("bearer ")) {
return authorization.substring(7);
}
return null;
};
const token = getTokenFrom(req);
if (token) {
jwt.verify(token, "shhhhh", (err, decoded) => {
if (err) return new ForbiddenResponse().Send(res);
let permission = decoded.info.permission;
let item = permission.find((x) => x.permissionId == access);
if (!item) {
return new ForbiddenResponse().Send(res);
} else {
next();
}
});
}
}
}
i add the argument name access to input of AccessUser in this middlware :
async AccessUser(access,req, res, next)
and i want to need compare the access with x.permissionId . but it show me this error :
(node:2168) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'authorization' of undefined
this error for this line :
const authorization = req.headers["authorization"];
and i use this middlware by this :
router.post(
"/Create",
access.AccessUser("Role:Add")
);
now whats the problem ? how can i use the middllware with input argument ?????
AccessUser is not a express middleware, the method signature has to be (req,res,next).
You can get around this if you define AccessUser as a factory function (there's no need to define it async as you're not awaiting any async call):
class AccessUser {
accessUser(access) {
return function (req, res, next) {
const getTokenFrom = (req) => {
const authorization = req.headers["authorization"];
if (authorization && authorization.toLowerCase().startsWith("bearer ")) {
return authorization.substring(7);
}
return null;
};
const token = getTokenFrom(req);
if (token) {
jwt.verify(token, "shhhhh", (err, decoded) => {
if (err) return new ForbiddenResponse().Send(res);
let permission = decoded.info.permission;
let item = permission.find((x) => x.permissionId == access);
if (!item) {
return new ForbiddenResponse().Send(res);
} else {
next();
}
});
}// TODO: handle case if no token exists?
}
}
}
module.exports = AccessUser;
Then use it like this:
const AccessUserMiddleware = require('./path-to-access-middleware');
const AccessUser = new AccessUserMiddleware();
app.get('/', AccessUser.accessUser("Role:Add"));

Nodemailer - cb is not a function?

i create an function to send email with nodemailer, but after run my console throw me:
TypeError: cb is not a function
at tryHandleCache (C:\Users\Maciek\Desktop\GoParty\backend\node_modules\ejs\lib\ejs.js:226:12)
at Object.exports.renderFile (C:\Users\Maciek\Desktop\GoParty\backend\node_modules\ejs\lib\ejs.js:437:10)
at Object.fn (C:\Users\Maciek\Desktop\GoParty\backend\api\controllers\user\create.js:47:28)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
my function to sendEmails.js
const transporter = require('nodemailer').createTransport(sails.config.custom.email)
module.exports = {
inputs:{
to: { type:'string', required:true },
subject: { type:'string', required:true},
html: {type:'string', required:true}
},
exits:{
success: {
description: 'All done.'
}
},
fn: async function(inputs, exits){
const options = {
from: sails.config.custom.email.auth.user,
to: inputs.to,
subject: inputs.subject,
html: inputs.html
}
transporter.sendMail(options, (err, info) => {
if(err){
return exits.error(err)
}else return exits.success(info.response)
})
}
}
my create.js where i must send email with correct variables:
const ejsVariable = {
activeCode: inputs.activateCode
}
// const html = await ejs.renderFile(templatePath, ejsVariable)
// const subject = 'EventZone - potwierdzenie rejestracji'
// const res = await sails.helpers.email.sendEmail(inputs.email, subject, html)
// if(!res){
// return this.res.badRequest('Confirmation email has not been send.')
// }
thanks for any help
ejs.renderFile takes 4 parameters, the last one is a function. Example usage:
ejs.renderFile(filename, data, options, function(err, str){
// str => Rendered HTML string
});
it doesn't return a promise so you can't await it.
try replacing
const html = await ejs.renderFile(templatePath, ejsVariable)
const subject = 'xxx'
const res = await sails.helpers.email.sendEmail(inputs.email, subject, html)
with
ejs.renderFile(templatePath, ejsVariable, async (err, html) => {
const subject = 'xxx'
const res = await sails.helpers.email.sendEmail(inputs.email, subject, html)
})
UPDATE
you can use util.promisify to make the ejs.renderFile function return a promise and thus work with async await like so:
const util = require('util') //first import `util`
....
const asyncEjsRenderFile = util.promisify(ejs.renderFile)
const html = await asyncEjsRenderFile(templatePath, ejsVariable)
const subject = 'xxx'
const res = await sails.helpers.email.sendEmail(inputs.email, subject, html)

Return value to variable from function

I am looking to return a value to a varible when I call the function in nodejs.
The output I am looking for is "Calling From Glasgow to Euston"
The output I am getting is "Calling From undefined to undefined"
Code is the following.
function trainstation(stx, callBack) {
MongoClient.connect(ttdb, function(err, db) {
if (err) throw err;
var dbo = db.db("ttdb");
var collection = dbo.collection("tlc");
var find = collection.find( { "Stanox" : stx } );
find.toArray(function(err, result) {
if (err) throw err;
db.close();
return callBack(result);
});
});
};
function gettrain(){
var ts1 = trainstation(9531, function(x){
return x[0]['Station Name'];
});
var ts2 = trainstation(31033, function(x){
return x[0]['Station Name'];
});
console.log("Calling From", ts1, "to", ts2);
};
gettrain();
Thanks :)
I don't use the MongoDB package and I don't have MongoDB up & running right now to test this, so I've written this code purely based on a quick read of the reference documentation. Perhaps you can test this and we'll fix any minor issues. Copy this code to a new source file and test it.
What I've done is to take advantage of the MongoDB package's promise features. You can see that the code is more linear and simpler to follow.
const MongoClient = require('mongodb').MongoClient;
const ttdb = 'mongodb://localhost:27017'; // or your DB URL
const trainstation = async (Stanox) => {
const client = MongoClient(ttdb);
await client.connect();
const dbo = client.db("ttdb");
const collection = dbo.collection("tlc");
const result = await collection.find({Stanox}).toArray();
client.close();
return result;
};
const gettrain = async () => {
const ts1 = await trainstation(9531);
const ts2 = await trainstation(31033);
const sn1 = ts1[0]['Station Name'];
const sn2 = ts2[0]['Station Name'];
console.log("Calling From", sn1, "to", sn2);
};
gettrain();

How to convert string "req.body" to data (function)?

I make a function checkCompanyPermit with paramater companyIdSource and array allowed.
Example:
companyIdSouce: "req.body.companyId", "req.params.companyId"...
allowed: "user", "admin"...
With parameter companyIdSource as string, I want to convert it to data. It's worked if I use eval(companyIdSource) but it's bad. How can I do another?
I try use Function("return " + companyIdSource)() but it return an error: req is not defined.
const checkCompanyPermit = (companyIdSource, ...allowed) => {
return async (req, res, next) => {
try {
const companyId = eval(companyIdSource) //Bad code, change another code
const company = await Company.findById(companyId)
//... some code
} catch (error) {
next(error)
}
}
}
checkCompanyPermit("req.body.companyId", "manager")
Since you already have access to the req object in your middleware, there is no need to pass the full string representation for req.body.companyId, just the property you need to check will suffice. Use the bracket notation to access the value from req.body object i.e.
const checkCompanyPermit = (companyIdSource, allowed) => {
return async (req, res, next) => {
try {
const companyId = req.body[companyIdSource]
const company = await Company.findById(companyId)
//... some code
} catch (error) {
next(error)
}
}
}
checkCompanyPermit("companyId", "manager")
It's Working For You.
const ObjectId = require('mongodb').ObjectId;
const checkCompanyPermit = (companyIdSource, ...allowed) => {
return async (req, res, next) => {
try {
const companyId = ObjectId('companyIdSource') //Replace here new code
const company = await Company.findById(companyId)
//... some code
} catch (error) {
next(error)
}
}
}
checkCompanyPermit("req.body.companyId", "manager")

Categories

Resources