Can i call a function from inside mustache templates which takes parameters? - node.js

I have a function defined in user_helper.js which generally returns value.
When I call getUserInfo() (in user_helper.js) from mustache template, it normally returns a String. But when I want results from mongoose query it returns NULL and not even shows any error.
index.js
router.get("/home", (req, res) => {
Profile.find()
.then(profile => {
res.render("index", {
userID: req.session.userID,
helper: require("../helpers/user_helper")
});
})
.catch(err => {
res.status(400).send("Unable to fatch");
});
});
module.exports = router;
user_helpert.js
var users = {
getUserInfo: function() {
return function(userID, render) {
var query = {_id:userID};
User.findOne(query, function(error, user) {
// Inside, return nothing
if (error) {
return error;
} else {
return user;
}
});
return "Some Text"; //This one's return result
};
}
};
module.exports = users;
mustache template
{{#helper.userInfo}}{{ userID }}{{/helper.userInfo}}
It should returns user information from database.
Can anyone knows about this or any better approach ?

There are many issues in your function.
The first one is that the query variable does not exist in the getUserInfo function. So the User.findOne() can't be executed.
The second error is that the User.findOne() method is asynchronous, so you won't be able to return a value as expected.
You should modify your /home route in the index.js to retrieve the user:
router.get("/home", (req, res) => {
User.findOneById(req.session.userID)
.then(user => {
res.render("index", {
user: user
});
})
.catch(err => {
res.status(400).send("Unable to fetch");
});
});
And in your template:
{{user.id}}

Related

Deleting the model data through lodash and save() not persisting model in mongodb

I am trying to remove one object from the User collection like this
router.post('/accept-trades', function (req, res, next) {
const {senderName, receiverName, senderId} = req.body;
const user = req.user;
console.log(senderName, receiverName);
if (senderName) {
User.findOne({ name: senderName })
.then(sender => {
_.remove(user.receivedTradeRequest, {username: senderName});
_.remove(sender.sentTradeRequest, {username: receiverName});
console.log('user.receivedTradeRequest', user.receivedTradeRequest);
console.log('\n\nuser.sentTradeRequest', user.sentTradeRequest);
async.parallel([
function (cb) {
user.save()
.then(isSave => {
cb(null, true);
})
.catch(err => {
cb(err, null);
});
},
function (cb) {
sender.save()
.then(isSave => {
cb(null, true);
})
.catch(err => {
cb(err, null);
});
}
], (err, results) => {
if (err) {
return res.status(500).json({
message: 'Error: Trade is invalid as Card is already traded!',
});
}
res.send('done');
//res.redirect('/trade');
});
})
.catch(err => {
throw err;
});
} else {
return res.status(500).json({
message: 'Only accessible to logged in users!',
});
}
});
Here, user is accessed by req.user (i'm using passport).
When i log the user after removal, user.receivedTradeRequest and sender.sentTradeRequest printing empty array which is the correct behaviour.
But when i see the mongodb the array still present for the username.
Could you please suggest what is wrong with the code ?
PS: I know about the mongodb $pull for removal. I am doing some other computation on the user data so had to do with above approach.
I was able to solve it by re-assigning the array after removing the element. Used _.filter instead of _.remove solves the problem.
One thing i don;t understand is the lodash _.remove update the original array after deletion but that clearly is not the case here.

Issue with update in Mongoose

I have wrote a simple Update function. Its working fine for some minutes and then again its not working. Where I am going wrong? Please help me. I use PUT as my method.
code
accept = (req, res) => {
this._model.update({
user: new mongoose.Types.ObjectId(req.params.uid)
}, {
$set: {
status: 'active'
}
}, (err, obj) => {
if (err || !obj) {
res.send(err);
} else {
res.send(obj);
}
});
}
Model
{
"_id":"5d3189a00789e24a23438a0d",
"status":"pending",
"user":ObjectId("5d3189a00789e24a23438a0d"),
"code":"CT-123-345-234-233-423344",
"created_Date":"2019-07-19T09:13:04.297Z",
"updated_Date":"2019-07-19T09:13:04.297Z",
"__v":0
}
Request
api.abc.com/api/accept/5d3189a00789e24a23438a0d
Sometime it is returing values and sometime null.
You can use the following code to ensure the model is tied to a connection. This could be an issue of connection to the database.
const config = require('./config');
console.log('config.database.url', config.database.url);
return mongoose.createConnection(config.database.url, {
useMongoClient: true
})
.then((connection) => {
// associate model with connection
User = connection.model('User', UserSchema);
const user = new User({
email: 'someuser#somedomain.com',
password: 'xxxxx'
});
const prom = user.update();
// Displays: 'promise: Promise { <pending> }'
console.log('promise:', prom);
return prom
.then((result) => {
// Don't see this output
console.log('result:', result);
})
.catch((error) => {
// Don't see this output either
console.log('error:', error);
});
})
.catch((error) => {
console.log(error);
});
I think you need to use promise or async/await, try this
accept = async (req, res) => {
try {
const result = await this._model.update({
user: new mongoose.Types.ObjectId(req.params.uid)
}, {
$set: {
status: 'active'
}
});
return res.send(result);
} catch (e) {
return res.send(e);
}
};

How to return data i got from database, from model back to controller

I am using Nodejs and cloud firestore as a database, i got the right data from database (logout) in model but after returning it back to controller i can not got it
// this is controller:
CheckPhoneNumber = (req, res) => {
// getting data from json
var json = {
// this is the entry ==> PhoneNumber : 123456789
PhoneNumber: req.body.PhoneNumber
}
// calling model function
console.log('this is from controller before calling database');
var user = model.CheckPhoneNumber(json.PhoneNumber)
.then(function () {
console.log('this is from controller after calling database');
console.log(user);
return user;
}).catch(err => {
return 'Error in controller awaiting ', err;
});
// outputting to Postman
return res.json(Promise.resolve(user));
}
and that controller calls the below model
// this is model :
// importing configure of database
const config = require('../config/main');
// this is for updates from google to firestore
config.db.settings({ timestampsInSnapshots: true });
// setting root of users database
const usersRoot = config.db.collection( my root here );
// takes json and return that user which phone number belongs to (actually it gets user by phone number )
async function CheckPhoneNumber(PhoneNumber) {
// getting data from database
var user;
user = await usersRoot.where('PhoneNumber', '==', PhoneNumber).get()
.then(async snapshot => {
if (snapshot.empty) {
return 'No matching documents.';
}
return await snapshot.forEach(async doc => {
console.log('your user is : ');
user = await doc.data();
console.log(user);
console.log('this is from model after calling database');
return await user;
});
}).catch(err => {
// console.log('Error getting documents',err);
return 'Error getting documents', err;
});
console.log('this is user befor returning : ');
console.log(user);
return user;
}
and this is the output of console in windows OS
this is from controller before calling database
this is from model after calling database
{ ... there is here some data ... }
this is from controller after calling database
Promise { <'pending'> }
I expect to get the data i returned from controller speicially after i await it to get data from database in the last line of console
It's because your user is a promise object.
You may want to respond in this block like,
model.CheckPhoneNumber(json.PhoneNumber)
.then(function (user) {
console.log('this is from controller after calling database');
console.log(user);
res.json(user)
})
.catch(err => {
res.json('error')
});
Or, you do it this way:
// make you route function async
CheckPhoneNumber = async (req, res) => {
...
// then you could
try {
const user = await model.CheckPhoneNumber(json.PhoneNumber)
res.json(user)
} catch (e) {
res.json('error')
}
change your model to:
async function CheckPhoneNumber(PhoneNumber) {
// getting data from database
try {
var snapshot = await usersRoot.where('PhoneNumber', '==', PhoneNumber).get()
if (snapshot.empty)
return "No"
var datas = [];
snapshot.forEach(doc => {
datas.push(doc.data())
})
return datas;
} catch (e) {
console.error(e);
}
}

Correct way to figure out what rejection a promise had?

I have an API / express router:
router.post("/signup", async function (req, res) {
try {
var user = await controllers.user.register(req.body.username, req.body.password);
req.session.user = user;
res.json(user);
} catch (e) {
res.status(500).json("DB Error");
}
});
Currently, on error, it returns 500 DB error. This is my controller:
function register(username, password) {
return new Promise((resolve, reject) => {
User.findOne({ username: username }).lean().exec((e, doc) => {
if (e) reject(e);
if (doc) {
reject("Username already exists.");
} else {
var user = new User({ username, password: hash(password) });
user.save((e) => {
if (e) reject(e);
else {
delete user.password;
resolve(user);
}
});
}
});
});
}
What's the right way to return a 400 if username already exists, and a 500 if it was a database error?
Mongoose already uses promises, the use of new Promise is promise construction antipattern.
Express doesn't have the concept of controllers, there are only route handlers and middlewares. Since register should be very aware of the way it will be used in a response, there may be no need for another level of abstraction above route handler. There will be no problem when a function has access to handler parameters and can form a response in-place.
It can be:
router.post("/signup", async function (req, res) {
try {
const { body, password } = req.body;
const user = await User.findOne({ username: username }).lean();
if (user) {
res.status(400).json("Username already exists");
} else {
...
res.json(user);
}
} catch (e) {
res.status(500).json("DB Error");
}
});
In case route handler needs to be reused in multiple places with some variations, it could be refactored to higher-order function or some other helper that is aware of original req and res parameters.
You can change the way you are rejecting the Promise. I'd suggest something like:
function register(username, password) {
return new Promise((resolve, reject) => {
User.findOne({ username: username }).lean().exec((e, doc) => {
if (e) reject(500);
if (doc) {
reject(400);
} else {
var user = new User({ username, password: hash(password) });
user.save((e) => {
if (e) reject(500);
else {
delete user.password;
resolve(user);
}
});
}
});
});
}
And in the route:
router.post("/signup", async function (req, res) {
try {
var user = await controllers.user.register(req.body.username, req.body.password);
req.session.user = user;
res.json(user);
} catch (e) {
res.status(e).json(e == 400 ? "Username already exists." : "DB Error");
}
});

integration tests, can't return an array NodeJS/Mocha

Hey I want return an array in integration tests,
I have a function in which tables are retrieved. Function expect object req.user._id, so I create it, next I create integration test, but when i run I have return empty object, could someone tell me what I have to do to get returned array?
function :
.get('/boards-list', function (req, res) {
Board.find({ 'users': req.user._id })
.then((board) => {
res.json(board);
})
.catch((err) => {
res.status(404).json('Nie można pobrać tablic.')
})
})
mocha :
describe('/boards-list', () => {
it('it should GET all the boards', (done) => {
var req = {};
req.user = {};
req.user._id = "ObjectId('5a8db5d449c0572dbc60548c')";
chai.request(server)
.get('/boards-list')
.send(req)
.end((err, res) => {
console.log(res.body);
// res.should.have.status(200);
// res.body.should.be.a('array');
// res.body.length.should.be.eql(0);
done();
});
});
});
I think the problem is with the id you are passing:
req.user._id = "ObjectId('5a8db5d449c0572dbc60548c')";
Try to pass it like this:
req.user._id = "5a8db5d449c0572dbc60548c";

Resources