I'm new to Node.js and am trying to pass some data from my DB model back to the router but I'm unable to find a solution. I have the following route file that makes a call to model:
Route file:
var express = require('express');
var router = express.Router();
var db = require('../db');
var customers = require('../models/customers');
db.connect(function(err) {
if (err) {
console.log('Unable to connect to MySQL.')
process.exit(1)
}
});
router.post('/', function(req, res) {
customers.checkPassword(req.body.cust_id, req.body.password);
res.sendStatus(200);
});
Model file:
var db = require('../db.js');
module.exports.checkPassword = function(cust_id, password) {
var sql = "SELECT Password FROM Shop.customers WHERE ID =" + cust_id;
db.get().query(sql, function (err, res, fields) {
result = res[0].Password;
if (err) throw err
});
};
My question is: how could I pass the queried result Password back to my Route file so that I can do this:
console.log('Password is', result);
I appreciate any help on this.
I'd use a promise
Model file
module.exports.checkPassword = function(cust_id, password) {
return new Promise(function(resolve, reject) {
const sql = "SELECT Password FROM Shop.customers WHERE ID =" + cust_id;
db.get().query(sql, function (err, res, fields) {
if (err) return reject(err)
result = res[0].Password;
return resolve(result);
});
});
};
Route file
var express = require('express');
var router = express.Router();
var db = require('../db');
var customers = require('../models/customers');
db.connect(function(err) {
if (err) {
console.log('Unable to connect to MySQL.')
process.exit(1)
}
});
router.post('/', function(req, res) {
customers.checkPassword(req.body.cust_id, req.body.password)
.then((result) => {
// DO: something with result
res.status(200).send();
})
.catch(console.log); // TODO: Handle errors
});
With async/await
router.post('/', async function(req, res) {
try {
const result = await customers.checkPassword(req.body.cust_id, req.body.password)
// DO: something with the result
} catch (e) {
console.log(e); // TODO: handle errors
} finally {
res.status(200).send();
}
});
I assume console.log('Password is', result); is just for test prupose, obviously you should never log a password! Also I suggest to move the callbabck of the routes do a different module, to improve code redability.
You might also find useful promise-module module on npm, basically a promise wrapper around mysql.
You can delegate the credential control to another function in your DB file where you can decide on what kind of data you want to return on success and failure to find such data. Then you can access it from where you are calling it.
Related
I was recently using a function to upload files to a mongodb database successfully. However after moving those functions into a file (to clean up) and exporting that file then requiring it in my route, the database now creates documents with only null values like so:
_id:ObjectId("xxxxxxxxxxxxxxx")
name:null,
value:null,
image:null,
desc:null
I don't know what might be causing this, I am logging the argument object that i'm trying to insert from inside the function 'insertProducts' and the item.name is not null. Sorry I'm new to mongodb :/
maybe someone can point me in the right direction?
CRUD.js
const mongodb = require('mongodb');
const MongoClient = mongodb.MongoClient;
const removeProducts = function(req,res){
MongoClient.connect('mongodb://localhost', (err, client) => {
if (err) {
throw err;
}
let db = client.db('account-app');
let products = db.collection('products');
let users = db.collection('users');
try{
products.remove({ _id: req.body.id }, function(err) {
if (!err) {
console.log('removed item')
}
});
}
catch(err){
console.log('Error while inserting', err)
}
client.close()
res.redirect('/addItems')
})
}
const insertProducts = function(item,res){
console.log("item name",item.name)
MongoClient.connect('mongodb://localhost', (err, client) => {
if (err) {
throw err;
}
let db = client.db('account-app');
let products = db.collection('products');
try{
products.insertOne(item)
console.log('item inserted')
}
catch(err){
console.log('Error while inserting', err)
}
client.close()
res.redirect('/admin/addItems')
})
}
module.exports={removeProducts: removeProducts, insertProducts: insertProducts}
my admin route that requires the crud functions
const crudOps = require('../utils/admin/CRUD') //require CRUD functions
// Adding new items
// --------------------------------------------------
router.post('/addNewItems', (req, res, next) => {
console.log(req.body.name)
let item = {
name:req.body.name,
file: binary(req.files.image.data),
value: req.body.value,
desc: req.body.desc
}
crudOps.insertProducts(item, res)
});
That connection URL looks wrong. Generally, it has the format:
mongodb://localhost:27017/mydatabase
Try replacing the connection string with the appropriate one for your database and see if that works. Also, the docs normally have insertOne statements like this so maybe that is the issue?
products.insertOne(item, function(err, r) {
console.log('item inserted')
res.redirect('/admin/addItems')
db.close();
});
I'm trying Koa instead of express and I have a problem returning ctx.
Here is my code :
router.get("/user/:id", async (ctx, next) => {
mongodb.connect(url, { useNewUrlParser: true }, (err, db) => {
if (err)
throw ("error => " + err);
else {
var dbo = db.db("test");
dbo.collection("users")
.find({})
.toArray((err, res) => {
if (err)
throw ("error => " + err);
db.close();
console.log(res);
ctx.body = {
"message": "GOT IT"
}
})
}
});
});
The problem is that ctx is unknown in the callback.
Any idea on how I can put it into the callback?
btw res is filled properly.
Thanks for help!
Maybe the problem with the callback has to do that you first have to wait for the
dbo.collection("users").find({})
And the do
toArray()
I use the koa-mongo library.
This library inject mongo into the context.
Open and close mongodb connection is not needed.
server.js
import Koa from 'koa'
import Mongo from 'koa-mongo'
const app = new Koa()
app.use(new Mongo(dbConfig))
In the router
let db = ctx.mongo
const result = await db.collection("users").find({})
if (!result) {
return []
}
return result.toArray()
I am newbie in ExpressJs and module pattern in my project. Now, i am stuck that how to use created controller function in another controller. Please look at example :-
menu.ctrl.js
------------
module.exports.save=function(req,res,next){
//here some logic
//somethings like validate req.body,etc
menu.save(function(err){
if(err) return next(err);
res.json({msg:'menu save'})
})
}
user.ctrl.js
------------
var user=require('./user.model')
var menuCtrl=require('./menu.ctrl')
module.exports.save=function(req,res,next){
//here some logic
user.save(function(err){
if(err) return next(err);
//HERE I WANT TO USE `menuCtrl.save()` function
res.json({msg:'success'});
})
}
Decoupling your controller logic from your model logic will allow you reuse logic and make your application easier to maintain.
The idea is that controllers' purpose is to format input and output to and from you application, while models handle actual data manipulation. (This is a typical Rails-like MVC pattern for REST APIs)
To your example:
menuController.js
var menuModel = require('./menuModel');
module.exports.save = function(req, res, next) {
menuModel.save(req.body, function(err) {
if(err) return next(err);
res.json({msg:'menu save'})
});
};
menuModel.js
module.exports.save = function(body, callback) {
// Save menu to the DB
menu.save(body, callback);
};
userController.js
var userModel = require('./userModel');
module.exports.save = function(req, res, next) {
userModel .save(function(err){
if(err) return next(err);
res.json({msg:'success'});
});
}
userModel.js
var menuModel = require('./menuModel');
module.exports.save = function(body, callback) {
// Save user to the DB
user.save(body, function(err, res) {
if (err) return callback(err);
menuModel.save(body, callback);
});
};
Rule of thumb, keep as less business logic as possible in controllers.
//Here is a solution if you are using same route file
//
var getNotificationSetting = async function (user_id) {
let params = {}
params = await NotifcationSetting.findAll({
where: { ns_user_id : user_id },
});
return params;
}
//now calling in action
router.get('/', async function(req, res, next) {
let params = {}
//for setting section
params = await getNotificationSetting(req.session.user.user_id);
});
My document is not getting deleted from the collections. Iam also not getting any error. The http transaction is perfectly fine.
// Node Module dependencies
var express = require('express');
var router = express.Router();
// Local Module dependencies
var common = require('./common.js');
//var request = require('request');
var db =common.conn;
var Question = require('../model/questions');
router.route('/postquestion')
.post(function (req, res) {
var item = new Question(req.body);
//console.log(item);
//=======calling postdata method=====//
postQuestion(item, function (result) {
res.json(result);
});
});
router.route('/deletequestion')
.delete(function (req, res) {
console.log(req.body._id);
Question.collection.deleteOne({_id:req.body._id},function(err,question){
if(err) throw err;
console.log('the document is deleted')
res.send(question);
});
})
function postQuestion(item, fn) {
item.save(function (err) {
if (err) console.log(err);
fn(item);
});
}
module.exports = router;
postquestion function is working perfectly fine and the database is getting updated. When i use postman for raising a delete request and send the below json.
{
"_id": "57bc442c4925180b067f075b"
}
iam getting a response like the below.
{
"ok": 1,
"n": 0
}
When i check the database in robomongo i see the document is not deleted. Am i missing something to be done. Is there anything else to be done.....!
MongoDB uses ObjectID to index document.
If you want to delete object using Mongo ID you have to instanciate an ObjectID.
https://docs.mongodb.com/manual/reference/method/db.collection.deleteOne/
var ObjectID = require('mongodb').ObjectID;
router.route('/deletequestion')
.delete(function (req, res) {
console.log(req.body._id);
const _id = new ObjectID(req.body._id);
Question.collection.deleteOne({_id:_id},function(err,question){
if(err) throw err;
console.log('the document is deleted')
res.send(question);
});
})
if nothing works, try the following...
app.delete("/api/posts/:id",(req,res,next)=>
{
Post.deleteOne({_id: req.param.id})
.then(result=>{
console.log(result);
});
//console.log('Post Deleted on node JS');
res.status(200).json({message: 'Delete'});
});
If you are using MongooseJS, you just need to do Question.deleteOne({...}), you don't need to do theQuestion.collection...` thing. Unless you have stuff wired up differently in your Model
I am using the Express framework and I have the following in one of my route files:
var allUsersFromDynamoDb = function (req, res) {
var dynamodbDoc = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: "users",
ProjectionExpression: "username,loc,age"
};
dynamodbDoc.scan(params, function (err, data) {
if (err) {
console.error("Unable to query. Error:", JSON.stringify(err));
res.statusCode = 500;
res.send("Internal Server Error");
} else {
console.log("DynamoDB Query succeeded.");
res.end(JSON.stringify(data.Items));
}
});
}
I am using the above function in one of my routes:
router.get('/users', allUsersFromDynamoDb);
Now the callback that I am defining while making a call to the "scan" on dynamodbDoc can be pretty useful if defined as a separate function. I can re-use that for some of my other routes as well.
But how can I can still get access to the "res" inside this new function?
I think I should be using "closure" but I can't seem to get it exactly right. I think I would need to maintain the signature of the new callback function to expect 2 params, "err" and "data" as per the following page:
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#scan-property
Any ideas on how this can be done?
You can use that function as middleware of every routes you want http://expressjs.com/en/guide/using-middleware.html
The new route with the middleware:
var middlewares = require('./middlewares'),
controllers = require('./controllers');
router.get('/users', middlewares.allUsersFromDynamoDb, controllers.theRouteController);
The middleware (middlewares.js) where you pass your data to req so you can use that data everywhere you have req:
exports.allUsersFromDynamoDb = function (req, res, next) {
var dynamodbDoc = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: "users",
ProjectionExpression: "username,loc,age"
};
dynamodbDoc.scan(params, function (err, data) {
if (err) {
console.error("Unable to query. Error:", JSON.stringify(err));
next("Internal Server Error");
} else {
console.log("DynamoDB Query succeeded.");
req.dataScan = JSON.stringify(data.Items);
next();
}
});
};
And finally the controller (controllers.js):
exports.theRouteController = function (req, res) {
// Here is the dataScan you defined in the middleware
res.jsonp(req.dataScan);
};
Based on Michelem's answer here I tried something which makes things a bit cleaner and code more reusable:
var allUsersFromDynamoDb = function (req, res, next) {
var dynamodbDoc = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: "users",
ProjectionExpression: "username,loc,age"
};
dynamodbDoc.scan(params, function (err, data) {
req.err = err;
req.data = data;
next();
});
}
Now I declare another function:
var processUserResults = function (req, res, next) {
if (req.err) {
console.error("Unable to query. Error:", JSON.stringify(req.err));
res.statusCode = 500;
res.send("Internal Server Error");
} else {
console.log("DynamoDB Query succeeded.");
res.end(JSON.stringify(req.data.Items));
}
};
And finally this:
router.get('/users', [allUsersFromDynamoDb, processUserResults]);
All I need to do in the original "function(err, data)" callback is always set 2 values:
req.err = err
req.data = data
And call next(). And processUserResults can similarly be used for other routes.
Still curious to find out if there are any other efficient solutions.