How to assign 2 collection in nodejs using mongodb - node.js

My code is looks like bellow, how to asign two collection, in my case 'User' and 'Host', btw i'm using handlebars, it always return [] or no collection in hosting variable. Please need help
const User = require("../models/user");
const Host = require("../models/host")
exports.index = function (req, res, next) {
User.findById(req.session.userId).exec(function (error, user) {
const hosting = [];
if (error) {
return next(error);
} else {
if (user === null) {
var err = new Error("Not authorized! Go back!");
err.status = 400;
return next(err);
} else {
console.log(user);
const dataParse = user.toJSON();
Host.find({user_id:req.session.userId}).toArray(async (err, result)=>{
if (err) {
throw err;
} else {
for (i=0; i<result.length; i++) {
hosting[i] = result[i];
}
}
});
console.log(hosting)
//console.log(tes);
return res.render("dashboard/index", {title:'dashboard', layout:'dashboard', user:dataParse, host:hosting});
}
}
});
};
thanks in advance !

I am guessing with your code functions that you are using mongoose as MongoDB package, updated your code to work
var ObjectId = mongoose.Types.ObjectId;
const User = require("../models/user");
const Host = require("../models/host")
exports.index = function (req, res, next) {
User.findById(ObjectId(req.session.userId)).exec(function (error, user) {
const hosting = [];
if (error) {
return next(error);
} else {
if (user === null) {
var err = new Error("Not authorized! Go back!");
err.status = 400;
return next(err);
} else {
console.log(user);
const dataParse = user.toJSON();
Host.find({user_id: ObjectId(req.session.userId)},(err, result)=>{
if (err) {
throw err;
} else {
for (i=0; i<result.length; i++) {
hosting[i] = result[i];
}
console.log(hosting)
return res.render("dashboard/index", {title:'dashboard', layout:'dashboard', user:dataParse, host:hosting});
}
});
}
}
});
};

Related

Async handling issue in nodejs

I am new in nodejs. I am creating a basic API to get record by id. Everything is working fine. It is returning user data from database. But when i use password variable from response in same function it give me empty value whereas i am getting value in response. I think this is async issue but i dont know how to fix it.
This is API code
var express = require('express');
var db = require('../db/database');
var bcrypt = require('bcrypt');
const router = express.Router();
router.get("/:userId", (req, res, next) => {
let uid = req.params.userId;
db.query(`SELECT * FROM users WHERE u_id = ${uid}`, (err, data)=> {
if(!err) {
if(data && data.length > 0) {
var message = '';
if(data.u_password){
//var pass = data.u_password;
if(bcrypt.compare('123456', data.u_password)) {
// Passwords match
message = 'Passwords match';
} else {
// Passwords don't match
message = 'Passwords dont match';
}
}
res.status(200).json({
message:message,
});
} else {
res.status(200).json({
message:"User Not found."
});
}
}
});
});
database.js
var mysql = require('mysql');
const pool = mysql.createPool({
connectionLimit : 10,
host: 'localhost',
user: 'root',
password: '',
database: 'lost_and_found',
debug : false
});
function executeQuery(sql, callback) {
pool.getConnection((err,connection) => {
if(err) {
return callback(err, null);
} else {
if(connection) {
connection.query(sql, function (error, results, fields) {
connection.release();
if (error) {
return callback(error, null);
}
return callback(null, results);
});
}
}
});
}
function query(sql, callback) {
executeQuery(sql,function(err, data) {
if(err) {
return callback(err);
}
callback(null, data);
});
}
module.exports = {
query: query
}
Response
{"message":""}
Please change the bcrypt.compare code to following code. It is a callback function:
bcrypt.compare('123456', data.u_password, function(err, result) {
if (err) {
// Passwords don't match
message = 'Passwords dont match';
} else {
// Passwords match
message = 'Passwords match';
}
res.status(200).json({
message:message,
});
})
EDIT 1: Please update the method to following logic:
db.query(`SELECT * FROM users WHERE u_id = ${uid}`, (err, data) => {
if (err) {
throw err;
}
if (data && data.length > 0) {
var message = '';
if (data.u_password) {
bcrypt.compare('123456', data.u_password, function (err, result) {
if (err) {
// Passwords don't match
message = 'Passwords dont match';
} else {
// Passwords match
message = 'Passwords match';
}
res.status(200).json({
message: message,
});
})
}
res.status(200).json({
message: "User Not found."
});
}
res.status(200).json({
message: "User Not found."
});
});

Express value assignment after middleware: Value assigned to this primitive will be lost

I have in express two route handlers, one is a param callback middleware that executes when a parameter is matched, and the second one is executed too with the above parameter on a DELETE method.
The code is as below:
const findPlan = async function (req, res, next) {
try {
let projection = {};
let plan = await AppPlans
.findOne({_id: req.params.appPlanID, active: true})
.select(projection)
.exec();
if (!plan) {
let err = new Error("No plan found");
err.status = 404;
return next(err);
}
req.plan = plan;
return next();
} catch (err) {
return next(err);
}
};
const deletePlan = async function (req, res, next) {
try {
req.plan.active = false;
await req.plan.save();
return res.sendStatus(202);
} catch (err) {
return next(err);
}
};
The above gives me on the part req.plan.active = false the warning:
Value assigned to this primitive will be lost
Previously the warning was not shown while the findPlan function's Mongoose query was defined with a callback, as:
const findPlan = function (req, res, next) {
try {
let projection = {};
AppPlans
.findOne({_id: req.params.appPlanID, active: true})
.select(projection)
.exec(function (err, plan) {
if (err) {
return next(err);
}
else if(!plan){
let err = new Error("No plan found");
err.status = 404;
return next(err);
}
req.plan = plan;
return next();
});
} catch (err) {
return next(err);
}
};
Is there anything wrong, like an edge case, or is it just a false positive as I am seeing other cases of this warning being not correct.
When your passing values between middlewares in Express.js you should use res.locals to store values as this is the official documented approach. This could likely be the reason for the warning.
const findPlan = async function (req, res, next) {
try {
let projection = {};
let plan = await AppPlans
.findOne({_id: req.params.appPlanID, active: true})
.select(projection)
.exec();
if (!plan) {
let err = new Error("No plan found");
err.status = 404;
return next(err);
}
res.locals.plan = plan;
return next();
} catch (err) {
return next(err);
}
};
const deletePlan = async function (req, res, next) {
try {
res.locals.plan.active = false;
await res.locals.plan.save();
return res.sendStatus(202);
} catch (err) {
return next(err);
}
};

next(err) not stopping execution

I am create an authentication route for my backend API:
const express = require("express");
const jwt = require("jsonwebtoken");
const User = require("../models/User");
let router = express.Router();
router.post("/", (req, res, next) => {
const { username, phone, password } = req.body;
if (!(username || phone) || !password) {
let err = new Error("invalid parameters");
err.status = 400;
next(err);
}
// XXX: Perhaps a better way to do this
let params = {};
if (username) {
params.username = username;
}
if (phone) {
params.phone = phone;
}
User.findOne(params)
.then(user => {
if (!user) {
let err = new Error("invalid credentials");
err.status = 401;
next(err);
}
user.checkPassword(password, (err, isMatch) => {
if (err) {
next(err);
}
if (!isMatch) {
console.log("we get here");
let err = new Error("invalid credentials");
err.status = 401;
next(err);
}
console.log("we also get here");
res.send({
token: jwt.sign(
{
_id: user._id,
username: user.username,
phone: user.phone
},
req.app.get("jwtSecret")
)
});
});
})
.catch(err => {
next(err);
});
});
module.exports = router;
When passing in a valid username but invalid password I get the output:
we got here
we also got here
Error: Can't set headers after they are sent.
at ...
The error I presume is because next(err) is not stopping the execution flow and therefore a response is getting sent twice.
Why is next(err) not stopping the execution flow?
You need to return inside your function after you call next(err).
next(err) stops future routing, but it doesn't stop execution within your own function. So, you need to either be using if/else or return when you're done to stop other parts of your own function from executing.
Personally, I would uses promises for all my asnyc operations and not use a mix and match of promises and callbacks. Then, you can just reject and funnel everything to just your one .catch() at the end.
But, if you're going to stick with your mixture of promises and callbacks, you can add return statements like this:
router.post("/", (req, res, next) => {
const { username, phone, password } = req.body;
if (!(username || phone) || !password) {
let err = new Error("invalid parameters");
err.status = 400;
next(err);
return;
}
// XXX: Perhaps a better way to do this
let params = {};
if (username) {
params.username = username;
}
if (phone) {
params.phone = phone;
}
User.findOne(params).then(user => {
if (!user) {
let err = new Error("invalid credentials");
err.status = 401;
throw err;
}
user.checkPassword(password, (err, isMatch) => {
if (err) {
next(err);
return;
}
if (!isMatch) {
console.log("we get here");
let err = new Error("invalid credentials");
err.status = 401;
next(err);
return;
}
console.log("we also get here");
let token = jwt.sign({_id: user._id, username: user.username, phone: user.phone}, req.app.get("jwtSecret"))
res.send({token});
});
}).catch(err => {
next(err);
});
});
If you change your implementation of user.checkPassword() to return a promise instead of using a callback, then you can do it this way without mixing callbacks and promises:
router.post("/", (req, res, next) => {
function throwErr(msg, status) {
let err = new Error(msg);
err.status = status;
throw err;
}
Promise.resolve().then(() => {
const { username, phone, password } = req.body;
if (!(username || phone) || !password) {
throwErr("invalid parameters", 400);
}
let params = {};
if (username) {
params.username = username;
}
if (phone) {
params.phone = phone;
}
return User.findOne(params).then(user => {
if (!user) {
throwErr("invalid credentials", 401);
}
return user.checkPassword(password).then(isMatch) => {
if (!isMatch) {
throwErr("invalid credentials", 401);
}
let token = jwt.sign({_id: user._id, username: user.username, phone: user.phone}, req.app.get("jwtSecret"))
res.send({token});
});
});
}).catch(err => {
next(err);
});
});
The throwErr() calls will all end up in the .catch().

how to return a value or string from call back function in Nodejs, mongooose

I have a function that is inserting user credentials. I want to return value from a call back function...
var router = require('express').Router();
var User = require('../Models').users;
// function calling here
router.post('/signup', function (req, res)
{
var result = User.signUp(req.body);
res.send(result);
});
module.exports = router;
//implemetation of function
userSchema.statics.signUp = function signUp(obj) {
var user = new userModel(obj);
user.password = hash.generate(obj.password);
return user.save(function (err, newuser) {
if (err)
{
return 'Error occured during insertion..';
} else
{
return 'You have sign up successfully...';
}
});
}
I want to return the response as a string but it showing undefined. How should it be done?
var router = require('express').Router();
var User = require('../Models').users;
router.post('/signup', function (req, res)
{
var result = User.signUp(req.body, function(err, result){
if(err){
}
else{
res.send(result)
}
});
});
userSchema.statics.signUp = function signUp(obj, callabck) {
var user = new userModel(obj);
user.password = hash.generate(obj.password);
user.save(function (err, newuser) {
if (err)
{
callback( 'Error occured during insertion..');
} else
{
callback(null, newuser);
}
});
}
Use the callback i.e.
var router = require('express').Router();
var User = require('../Models').users;
// function calling here
router.post('/signup', function (req, res)
{
User.signUp(req.body,function(err,result){
res.send(result);
});
});
module.exports = router;
//implemetation of function
userSchema.statics.signUp = function signUp(obj,callback) {
var user = new userModel(obj);
user.password = hash.generate(obj.password);
return user.save(function (err, newuser) {
if (err)
{
callback('Error occured during insertion..',null);
} else
{
callback(null,'You have sign up successfully...');
}
});
}
Because of async nature .. Try this:
router.post('/signup', function (req, res)
{
var result = User.signUp(req.body, function(err, result){
if(err){}
else{res.send(result)}
});;
});
userSchema.statics.signUp = function signUp(obj, callabck) {
var user = new userModel(obj);
user.password = hash.generate(obj.password);
user.save(function (err, newuser) {
if (err)
{
callback( 'Error occured during insertion..',null);
} else
{
callback (null, 'You have sign up successfully...');
}
});
}

the variable i is not filled

I have declare the variable first. but if I do console.log(userinsertData) outside looping variable still not fill.
what i should do for solving this problem?
here my code:
var User = require('../models/user');
module.exports = {
myaction: function(req, res, next) {
var data = req.body,
userinsertData = [];
try {
data.forEach(function(item, index) {
var userdata = new User();
userdata.name = item.name;
userdata.age = item.age;
userdata.sex = item.sex;
userdata.save(function(err, data) {
if (err) {
res.send(err)
} else {
userinsertData.push(data);
}
});
})
} catch (e) {
res.json({
message: 'data not valid'
})
}
console.log(userinsertData);
res.json({
message: 'musician created!',
data: userinsertData
});
}
};
you should solve the problem as
async.eachSeries(data, function (info, callback) {
//here process your data and call callback() for next iteration
}, function (err) {
if (err) {
//this will be called after all iterations and in case of error
}else{
console.log('Well done :-!');
//this will be called after all interations successfully
}
});
this problem you are facing is because of asynchronous nature of nodejs and async helps you to introduce blocking.
Don't forget to include async
Use promise
var User = require('../models/user');
module.exports = {
myaction: function(req, res, next) {
var data = req.body,
userinsertData = [];
new Promise(function(resolve, reject) {
data.forEach(function(item, index) {
var userData = new User(item);
userData.save(function(err, data) {
// if error, reject
if(err) return reject(err);
// we have proceed all items in data, resolve it
else if(data.length - 1 === index) return resolve(userinsertData);
// not finished yet, keep proceeding
else userinsertData.push(data);
});
}).then(function(successResult) {
res.json({
message: 'musician created!',
data: successResult
});
}, function(errorResult) {
res.json({
message: 'data not valid'
});
});
}
};
Use callbacks
var User = require('../models/user');
module.exports = {
myaction: function(req, res, next) {
var data = req.body,
userinsertData = [];
function saveUser(callback) {
data.forEach(function(item, index) {
var userData = new User(item);
userData.save(function(err, data) {
// if error, return callback with error
if(err) return callback(err);
// we have proceed all items in data, return data
else if(data.length - 1 === index) callback(null, userinsertData);
// not finished yet, keep proceeding
else userinsertData.push(data);
});
}
saveUser(function(err, users) {
if(err) return res.json({message: 'data not valid'});
res.json({
message: 'musician created!',
data: users
});
});
}
};
This is what async package does internally

Resources