Template literal in MongoDB query with Mongoose - javascript

I'm trying to make a query with template literals, like this:
router.post('/login', middleware.isLoggedOut, function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
else
{
console.log(req.body);
var y=0;
User.findOne({'username': req.body.username, `privileges.${y}.region`: req.body.regiuni}, function(err, usr)
{
if(err)
{
console.log(err);
}
else
{
if(usr === null)
{
console.log("no usr");
}
else
{
req.logIn(usr, function(err)
{
if(err)
{
console.log(err);
}
return res.redirect('/users/' + user.username);
})
}
}
})
}
})(req, res, next);
});
I can't really get how I should use the template literal here "privileges.${y}.region" because right now it doesn't work. I get "unexpected template string" in the node shell, but vs code also seem not to interpret it as I want because it colors the code like the template literal is this:
: req.body.regiuni}, function(err, usr)
{
if(err)
{
console.log(err);
}
else
{
if(usr === null)
{
console.log("no usr");
}
else
{
req.logIn(usr, function(err)
{
if(err)
{
console.log(err);
}
return res.redirect('/users/' + user.username);
})
}
}
})
}
})(req, res, next);
});
module.exports = router;
Why does it happen and how can I fix this?

You need to have it inside of brackets, like
[`privileges.${y}.region`]: req.body.regiuni
It's an object, think about the way you'd access it.
Would you do
obj.`privileges.${y}.region`?
Nop, you'd use brackets
obj.[`privileges.${y}.region`]

Related

Why does this mongodb controller pass undefined back to route?

The app is using basic Node.js, Express, and MongoDB to return some data at different routes.
Route:
router.get('/api/v1/:collection', (req, res, next) => {
try {
const data = ApiController.getAllRecipes(req, res, next);
console.log(data);
res.send(data);
} catch(error) {
res.send(error);
}
});
The methods that query the database are contained within a simple controller:
module.exports = {
getAllRecipes: async (req, res, next) => {
try {
req.app.db.collection(req.params.collection).find({}).toArray((error, result) => {
if (result.length > 0) {
console.log(result);
return result;
} else {
let error = new Error();
error.statusCode = 404;
error.message = 'No API results found.';
next(error);
}
});
} catch (error) {
next(error);
}
}
};
Inside the controller, the console.log(result); returns the correct data that I would like to be handled within the route file. However, the console.log(data); in the Route file returns undefined, even within the try/catch block.
Am I missing something in passing the data from the controller back to the route? Thank you :)
Found a solution! Since the controller is asynchronous, it doesn't need to return data, but rather save it to res.locals and execute Express' next() method to continue with the route.
Updated Route:
router.get('/api/v:versionNumber/:collection', ApiController.getAllRecipes, (req, res, next) => {
res.send(res.locals.results);
});
Updated controller:
getAllRecipes: async (req, res, next) => {
try {
req.app.db.collection(req.params.collection).find({}).toArray((error, result) => {
if (result.length > 0) {
res.locals.results = result;
next();
} else {
let error = new Error();
error.statusCode = 404;
error.message = 'No API results found.';
next(error);
}
});
} catch (error) {
next(error);
}
}

Passport Js documentation Custom Callback syntax

I am using passport.js for my node app. In the Custom Callback section I found the following code(lets say it Code A):
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
My question is I am not able to understand passing (req, res, next) at the end. How the following code(lets say it Code B):
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
});
});
How Code B is different from Code A ?
If I simplify Code A then it will be like :
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(..){..})(req, res, next);
});
Further
passport.authenticate(..)(req, res, next);
which means expression like
function(..)(req,res, next)
My Question is more about understanding the syntax
function(..)(parameters)
authenticate() function is structured like this:
module.exports = function authenticate(passport, name, options, callback) {
// ...
return function authenticate(req, res, next) {
// ...
strategy.success = function(user, info) {
if (callback) {
return callback(null, user, info);
}
}
// ...
})
};
So it takes two series of parameters:
The first one (in your case 'local' and the callback function) is used to tell passport to authenticate you, and how to do it;
The second handles the function to control your app with req, res and next parameters.
Hope it helps you to understand!

Node.js doesn't show results status properly in api

I'm developing a simple rest API in Node.js, and it works middling.
This is my controller code:
...
exports.listById = function(id, callback) {
Course.findById(id, function(err, courses){
if(err){
callback({error: 'Not Found'});
}
else{
callback(courses);
}
});
}
And this is my route:
app.get('/courses/:id', function(req, res){
var id = req.params.id;
courseController.listById(id, function(resp){
res.status(200).json(resp);
});
});
This code works and show results of my collection in mongodb.
But the code below, doesn't show results with postman:
app.get('/courses/:id', function(req, res){
var id = req.params.id;
courseController.listById(id, function(err, resp){
if(err){
res.status(404).send(err);
}
else{
res.status(200).json(resp);
}
});
});
exports.listById = function(id, callback) {
Course.findById(id, function(err, courses){
if(err)
return callback(new Error('Not Found')); // You must return Error by standard
callback(null, courses); // You must set first argument (error) to null
});
}
...
// You can check that id is number
app.get('/courses/:id(\\d+)', function(req, res, next) {
var id = req.params.id;
courseController.listById(id, function(err, resp) {
if(err)
return next(err); // Pass error to error-handler (see link below)
res.status(200).json(resp);
});
Best practice for callback function is first argument as error and second as result.You should
exports.listById = function (id, callback) {
Course.findById(id, function (err, courses) {
if (err) {
callback(error);
}
else {
callback(null, courses);
}
});
}
while your route should look like this:
app.get('/courses/:id', function (req, res) {
var id = req.params.id;
courseController.listById(id, function (error, courses) {
if (error) return res.status(500) // internal server error
// if I remember correctly, sources is empty array if course not found
res.status(200).json(resp);
});
});

NodeJS error when rendering page:Cast to ObjectId failed for value "styles.css" at path "_id"

The error prevents my webpage from being rendered. As mentioned in the title, the error lies in styles.css, when I take this file out, I do not get any errors.
styles.css is included in a separate headers.ejs file which is added in all pages, but there is only one route for which the error is shown(/cats/new). I put up some some logs around my routes and it seems when I enter /cats/new/, I am automatically redirected to a new route (get /cats/:id). I am wondering if this is the cause of the error?
I have attached my routes and the full error message below:
routes:
var express = require('express');
var router = express.Router();
var User = require('../models/user.js');
var Cat = require('../models/cat.js');
var Comment = require('../models/comment.js');
//middleware
function isAuthenticated(req,res,next) {
req.isAuthenticated() ? next() : res.redirect('/login');
}
router.get("/", function(req,res) {
res.redirect("cats");
});
router.get('/cats', function(req,res) {
Cat.find({}, function(err, cats) {
if (err) {
console.log(err);
} else {
res.render('cats', {cats: cats});
}
});
});
router.get('/cats/new', isAuthenticated, function(req,res) {
console.log('went to /cats/new');
res.render('new', {user: req.user});
});
router.post('/cats', isAuthenticated, function(req,res) {
console.log('went to post /cats');
var name = req.body.name;
var image = req.body.url;
var owner = req.user.username
var description = req.body.description;
cat = new Cat({
name: name,
image: image,
owner: owner,
description: description
});
cat.save();
User.findById(req.user._id, function(err, user) {
if (err) {
console.log(err);
} else {
user.cats.push(cat);
user.save();
}
})
res.redirect('cats');
});
router.get('/cats/:id', function(req,res) {
var id = req.params.id;
Cat.findById(id).populate('comments').exec(function(err, cat) {
if (err) {
console.log('entering get /cats/:id');
console.log(err);
} else {
console.log('no errror yet');
console.log(cat.comments);
res.render('show', {cat:cat});
}
});
});
router.post('/cats/:id', isAuthenticated, function(req,res) {
console.log(isAuthenticated);
var id = req.params.id;
Cat.findById(id, function(err, cat) {
console.log('findById running');
if (err) {
console.log(err);
console.log('err finding cat');
res.redirect('/cats');
} else {
console.log('before Comment.create');
Comment.create(req.body.comment, function(err, comment) {
console.log('after Comment.create');
if (err) {
console.log(err);
} else {
console.log('right after 2nd else');
comment.author.id = req.user._id;
console.log(req.user._id);
console.log(req.user.username);
comment.author.username = req.user.username;
comment.cat = id;
comment.save();
console.log('after saving comment');
cat.comments.push(comment);
cat.save();
console.log('saved cat');
User.findById(req.user._id, function(err, user) {
if (err) {
console.log(err);
} else {
user.comments.push(comment);
user.save();
console.log('saved user');
}
});
console.log(comment);
res.redirect("/cats/" + cat._id);
}
});
}
});
});
router.get('/cats/:id/edit', function(req,res) {
var id = req.params.id;
Cat.findById(id, function(err, cat) {
if (err) {
console.log(err);
} else {
res.render('edit.ejs', {cat:cat});
}
});
});
router.put('/cats/:id', function(req,res) {
console.log('beginning /cat/:id');
Cat.findByIdAndUpdate(
req.params.id, req.body.cat, function(err, updatedCat) {
if (err) {
console.log(err);
} else {
console.log('------------ req.body.cat');
console.log(req.body.cat);
console.log('------------ updated cat');
console.log('updated cat');
res.redirect('/cat/' + req.params.id);
console.log('not redirecting?');
}
});
router.delete('/cats/:id',isAuthenticated, function(req,res) {
var id = req.params.id;
console.log('YOU ARE TRYING TO DESTROY A CAT!');
Cat.findByIdAndRemove(id, function(err) {
if (err) {
console.log(err);
res.redirect('/user');
} else {
res.redirect('/user');
}
});
})
});
module.exports = router;
Error:
entering get /cats/:id
{ [CastError: Cast to ObjectId failed for value "styles.css" at path "_id"]
message: 'Cast to ObjectId failed for value "styles.css" at path "_id"',
name: 'CastError',
kind: 'ObjectId',
value: 'styles.css',
path: '_id',
reason: undefined }
It seems you’re including styles.css using a relative path in your template.
So when you navigate to /cats/:id, it tries to load /cats/styles.css.
In order to avoid that, you have to use an absolute path (e.g.: /styles.css or /public/styles.css – I’d recommend serving static files from a dedicated base path).
Go to
<head>
and change
<link rel="stylesheet" href="style.css">
to
<link rel="stylesheet" href="/style.css">

Node/Express Rest API - How to throw an error from mssql

I'm quite new to both javascript and Node/Express, and it's probably a newbie question, but here goes...
I'm building a Rest API, and want to throw new Error(err.message) from this function:
function hentForfatter(id, callback) {
sql.connect(config, function(err) {
if(err) {
console.log(err);
callback(err);
}
new sql.Request().query('SELECT * from Forfatter where ForfatterID = ' + id).then(function(recordset) {
callback(recordset[0]);
})
.catch(function(err) {
console.log(err);
callback(err);
});
});
}
... so I can do this in my Express API route:
router.get('/:forfatterid/quizer/:quiz_id', function(req, res, next) {
try {
db.hentQuiz(1, function(result) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(result));
});
}
catch (error) {
res.status(404).send(error)
}
});
I can't get my head around how to do this... Anyone that can help? :)
In node, there is a convention that the first parameter of a callback should be the potential error.
function hentForfatter(id, callback) {
sql.connect(config, function(err) {
if(err) {
console.log(err);
return callback(err); //notice the return statement
}
new sql.Request().query('SELECT * from Forfatter where ForfatterID = ' + id).then(function(recordset) {
callback(null, recordset[0]); //notice I send null for the error
})
.catch(function(err) {
console.log(err);
callback(err);
});
});
}
(I'm not sure how you get form db.hentQuiz to hentForfatter.)
router.get('/:forfatterid/quizer/:quiz_id', function(req, res, next) {
db.hentQuiz(1, function(err, result) {
if(err) return res.status(404).send(error);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(result));
});
});
Try using two parameters if using callbacks:
callback(err, result)
And then check for
err and result.
In addition look up how promise chains work.

Categories