Create route Express.js and MySql - javascript

I am playing with Express.js and MySQL. I am trying to create a route in order to display data via API.
In my database, I have a price field and I am trying to display all properties in the a price range. 
SELECT * FROM properties
WHERE price BETWEEN 10000 AND 20000;
In my model.js file I set up like this:
Property.findBy = (valueMin, valueMax, result) => {
sql.query(`SELECT * FROM properties WHERE price BETWEEN ${valueMin} AND ${valueMax}`, (err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
if (res.length) {
console.log("No price: ", res[0]);
result(null, res[0]);
return;
}
result({ kind: "range" }, null);
});
};
In my controller.js file
exports.findMaxi = (req, res) => {
Property.findBy(req.params.valueMin, req.params.valueMax, (err, data) => {
if (err) {
if (err.kind === "not_found") {
res.status(404).send({
message: `Not found property for range ${req.params.valueMin} and ${req.params.valueMax}`
});
} else {
res.status(500).send({
message: "Error found property for range " + req.params.valueMin + req.params.valueMax
});
}
} else res.send(data);
});
};
And finally, my routes:
app.get("/properties/:valueMin&valueMax", propertis.findMaxi);
This route doesn’t work. I don’t know how to solve this problem. Can someone offer assistance?

I think it's because your route is like
app.get("/properties/:valueMin&valueMax", propertis.findMaxi);
you'll only be able to pass 1 value and the other is the string "&valueMax", so you can't change the value of valueMax... for example, if you want to have valueMin = 100, the query is like GET /properties/100&valueMax.
So, each value you want to pass in this way, use ':' before each variable, like
app.get("/properties/:valueMin&:valueMax", propertis.findMaxi);
and a query like //GET /properties/100&200 will work
But I think it's better to pass the variables as query params GET /properties?min=100&max=200

You most likely want to pass min and max as query parameters.
// GET /properties?min=10000&max=20000
console.log(req.query.min) // => '10000'
console.log(req.query.max) // => '20000'
The way you did is that you have one value that you can access with req.params and it is valueMin&valueMax (I don't think it is even valid to have a variable that contains & character).
You could have a route like /properties/:min/:max to access those two separately, or just use query parameters which is made for that purpose

Related

Creating new mongoose sub-doc and appending to existing parent doc

I'm building a website with a database using NodeJS, MongoDB, Express, Mongoose etc.
I have two schema set up: Events and a sub-doc schema Categories (among others).
The function pulls in array which contains the data needed to create several categories (this bit works) as well as the Event ID appended to the end.
The first few bits below just grab that ID, then remove it from the array (probably a better way to do this, but again, it works).
As mentioned above, the Categories then create correctly (and even do validation), which is amazing, BUT...
They don't get appended to the Event doc. The doc updates the "categories" field to an applicable number of "null" values, but I cannot for the life of me get it to actually take the IDs of the newly created categories.
I nabbed (and adjusted) the below code from somewhere, so this is where I'm at...
exports.addCategories = catchAsync(async (req, res, next) => {
const categories = req.body;
const length = categories.length;
const eventID = categories[length - 1].eventId;
categories.pop();
Event.findOne({ _id: eventID }, (err, event) => {
if (err) return res.status(400).send(err);
if (!event)
return res.status(400).send(new Error("Could not find that event"));
Category.create(categories, (err, category) => {
if (err) return res.status(400).send(err);
event.categories.push(category._id);
event.save((err) => {
if (err) return res.status(400).send(err);
res.status(200).json(category);
});
});
});
});
Currently the mongoose debug output is showing the following (which confirms that MOST of it is working, but the IDs just aren't being pulled correctly):
> Mongoose: events.updateOne({ _id: ObjectId("614bc221bc067e62e0790875")}, { '$push': { categories: { '$each': [ undefined ] } }, '$inc': { __v: 1 }}, { session: undefined })
Nevermind! I realised that "category" was still an array, rather than an element of the categories array as I'd assumed.
So I replaced that section with this, and now... it works!
Category.create(categories, (err, categories) => {
if (err) return res.status(400).send(err);
categories.forEach((category) => {
event.categories.push(category._id);
});
event.save((err) => {
if (err) return res.status(400).send(err);
});
});

pass a json result of a mysql query as a param to my ejs in Node/express

I have a query to get all my users. I have been doing res.json(rows) to display to screen until now. Now I want to pass the object obtain from the query to a ejs file and display it. If I do like my code below, the object pass is a string and I can´t iterate or obtain the fields.
What is the best way to achive what I´m trying to do?
router.get("/users", (req, res) => {
const connection = getConnection();
const newLocal = "SELECT * FROM client";
connection.query(newLocal,(err, rows, fields) => {
if (err) {
console.log("Error "+err);
res.sendStatus(500);
return;
}
// res.json(rows);
res.render("users.ejs", {users: JSON.stringify(rows)});
});
});
It's because you're turning your Array rows into a String. Remove JSON.stringify

how to properly send the response code from Node.js API

I have a simple node-based API, which needs to parse some JSON, save some data into Postgres, and then, send the appropriate response code (like http 201).
My code looks like this:
router.route('/customer')
.post(function(req, res) {
Customers = req.body;
var numberOfCustomers = Customers.length;
for(var i = 0; i < Customers.length; i++){
Customer = Customers[i];
console.log(Customer.Name + " " + Customer.Address);
var date = moment(new Date()).unix();
client.query(
'INSERT into customer (name, address, date_modified) VALUES($1, $2, $3) RETURNING id',
[Customer.Name, Customer.Address, date],
function(err, result) {
if (err) {
console.log(err);
status = 1;
} else {
console.log('row inserted with id: ' + result.rows[0].id);
if(numberOfCustomers === i) {
res.status(201).send({ message: "created" });
}
}
});
}
})
I'm getting this error:
_
http_outgoing.js:344
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
I need to account for the fact, that I'm performing my Postgres insert multiple times within a loop, so I can not send my response headers after just the first insert is done.
What is the most appropriate place within my 'POST' handler to put my res.status(201).send({ message: "created" });
?
Architectural decisions aside (for example, you might want a separate module that acts as an HTTP adapter to handle logic for sending response codes as opposed to doing it inside of your route controller), you can use promises to wait for all the inserts to finish and then send a single response code. For example, something like this:
var Promise = require('bluebird');
var query = Promise.promisify(client.query);
router.route('/customer')
.post(function(req, res) {
// all your logic, and then
return Promise.all(Customers.map(function() {
return query(sql, [Customer.Name, Customer.Address, date]);
})
.then(function() {
res.status(201).send({ message: 'Created' });
});
});
Check out the the bluebird docs for the API used in this example.
I'm unfamiliar with Postgres's API, but the concept should be similar: you need to wait for all the requests to your DB to be resolved first.
As stated above: Yes, async helpers such as Promises and async are beneficial for such matters. However, I do believe the 'best' way to solve this problem is to only use a single query. Instead of only performing one insert per query, batch them all up in to a single query like so:
INSERT into customer (name, address, date_modified)
VALUES
($1, $2, $3),
($4, $5, $6),
($7, $8, $9),
...
RETURNING id'
Suggestion
router.route('/customer').post(function(req, res) {
//Fetch customers
var customers = req.body;
//Store parameters and query inserts for db-query.
var params = [];
var inserts = [];
//For each customer
// - Add parameters for query
// - Build insert string
customers.forEach(function(customer){
inserts.push(
[
"($",
params.push(customer.Name),
", $",
params.push(customer.Address),
", ",
NOW(), //unnecessary to generate timestamp in js
")",
].join('')
)
});
//Build query
var query = 'INSERT into customer (name, address, date_modified) VALUES '+ inserts +' RETURNING id';
//Query database in a more simple fashion.
client.query(query, params, function(err, result) {
if (err) {
console.log(err);
status = 1;
} else {
res.status(201).send({ message: "created" });
});
}
})
If you're using ES6 you are able to simplify the string build operations by using string templating.
customers.forEach(function(customer){
var query = `($${params.push(customer.Name)}, $${params.push(customer.Address)}, NOW())`
inserts.push(query);
});
//and
var query = `
INSERT into customer (name, address, date_modified)
VALUES ${inserts}
RETURNING id
`;
The proper way be to do, I would also recommend you look into Async or lodash lib.
router.route('/customer')
.post(function(req, res) {
var Customers = req.body,
numberOfCustomers = Customers.length;
for(var i = 0; i < Customers.length; i++){
var Customer = Customers[i];
console.log(Customer.Name + " " + Customer.Address);
var date = moment(new Date()).unix(),
sql = 'INSERT into customer (name, address, date_modified) VALUES($1, $2, $3) RETURNING id';
client.query(sql, [Customer.Name, Customer.Address, date],
function(err, result) {
if (err) {
console.log(err);
res.status(500).json({message: "Server Error", err: err});
} else {
console.log('row inserted with id: ' + result.rows[0].id);
if (numberOfCustomers === i) {
res.status(201).send({ message: "Created" });
}
}
});
}
})

Send DBNull.Value instead of 'null' in nodeJS MySql

HOw can i send null value to database in node.js?
I am using MySql Package for node JS
and I have some null values to insert which I want to be stored in database as DBNull.Value( as in asp.net) and not as "null" or " ".
Also, I cannot skip any value to insert.
My code below:
var query=connection.query("insert into user_details(user_id,username,screenname,firstname,middlename,lastname,about_me,color_code,Gender,hobbies,occupation,member_of_group,profile_pic,address1,address2,city,pincode,phonenumber,EmailId1,EmailId2,createdate,updatedate) values('"+json.user_id+"','"+ json.username+"','"+json.screenname+"','"+json.firstname+"','"+json.middlename+"','"+json.lastname+"','"+json.about_me+"','"+json.color_code+"','"+json.Gender+"','"+json.hobbies+"','"+json.occupation+"','"+json.member_of_group+"','"+json.profile_pic+"','"+json.address1+"','"+json.address2+"','"+json.city+"',"+json.pincode+",'"+json.phonenumber+"','"+json.EmailId1+"','"+json.EmailId2+"','"+json.createdate+"','"+json.updatedate+"');",function(err,result){
if(!err){
connection.destroy();
callback(result);
}
else
{
console.log(err);
callback('error');
}
});
How can I do that???
First of all, you shouldn't directly concatenate (especially user submitted) values for security reasons and it's just plain tedious when you have a lot of concatenation going on.
Try this instead which makes it easier to work with and properly escapes your values:
connection.query('INSERT INTO user_details SET ?', json, function(err, result) {
connection.destroy();
if (err)
console.log(err);
callback(err, result);
});
or manually specify the values if the keys in the data source do not match up with column names:
var values = {
user_id: json.id,
username: json.user,
// ...
};
connection.query('INSERT INTO user_details SET ?', values, function(err, result) {
connection.destroy();
if (err)
console.log(err);
callback(err, result);
});
Secondly, typically callbacks use "error-first", so passing a real error object as the first argument is better.

MongooseJS Not saving to array properly

I want to append a value into my Mongoose array but my array never seems to update. I do the following:
In my controller, I append an eventName into the array eventsAttending like so:
$scope.currentUser.eventsAttending.push(event.eventName);
$http.put('/api/users/' + $scope.currentUser._id, $scope.currentUser)
.success(function(data){
console.log("Success. User " + $scope.currentUser.name);
});
I try to update the array like so:
// Updates an existing event in the DB.
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
User.findById(req.params.id, function (err, user) {
if (err) { return handleError(res, err); }
if(!user) { return res.send(404); }
user.markModified('req.body.eventsAttending');
user.save(function (err) {
if (err) { return handleError(res, err);}
return res.json(200, user);
});
});
};
But my array never seems to update. I've also tried the following:
// Updates an existing event in the DB.
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
User.findById(req.params.id, function (err, user) {
if (err) { return handleError(res, err); }
if(!user) { return res.send(404); }
var updated = _.merge(user, req.body);
updated.markModified('eventsAttending');
updated.save(function (err) {
if (err) { return handleError(res, err);}
return res.json(200, user);
});
});
};
With this approach, my array updates properly, but when I try to perform the http put after one time, I get an error saying Error: { [VersionError: No matching document found.] message: 'No matching document found.', name: 'VersionError' }
Here is my UserSchema:
var UserSchema = new Schema({
name: String,
username: String,
eventsAttending: [{ type: String, ref: 'Event'}],
});
If anyone could help that would be much appreciated.
My guess is the object returning from _.merge is no longer a Mongoose model and some information is getting lost in the transform. I would try manually setting all of the fields coming from the request and use events.attending.push() to add to the array, then saving the updated object and see what happens.
Your first example with markModified looks wrong. Looking at the documentation it should be the name of the field that is modified and it appears that you've put the source location for it.
user.markModified('user.eventsAttending')
However that should not be necessary if you use the push method as Mongoose overrides the built-in array function to track changes.

Categories

Resources