To pass to object data pug in Mongoose - javascript

The existing code was written as MySQL query and I am now working on converting it to Mongoose query.
I need to get five data sorted by the most recent subscription year from the main page.
The existing code brought this result value into an array. And data was delivered through pug view, and Mongoose seems to bring the result value of Object. In this case, I wonder how to deliver the data through Pug view.
I checked importing data from the terminal to the console.log, but an error called 'Error [ERR_HTTP_HEADERS_SENT]: Cannot set heads after they are sent to the client occurs and no data is passed to the pug. I wonder why this problem occurs.
[MySQL Query]
router.get("/", function (req, res, next) {
// Main page Profile Data Process
db.query(`SELECT * FROM user ORDER BY registerDate DESC LIMIT 5`, function (
error,
data
) {
// Log Error
if (error) {
console.log(error);
}
res.render("main", {
dataarray: data,
_user: req.user,
url: url
});
});
});
[Mongoose Query]
router.get("/", function (req, res, next) {
let dataarray = [];
let userData = db.collection("user").find().limit(5).sort({
"created_at": -1
});
userData.each(function (err, doc) {
if (err) {
console.log(err);
} else {
if (doc != null) {
dataarray.push(doc)
}
}
// console.log(dataarray.login)
console.log(dataarray);
res.render("main", {
dataarray,
_user: req.user
})
});
});
[pug file]
each profile in dataarray
.col-lg-4
img.rounded-circle(src=`${profile.avatar_url}` alt='Generic placeholder image' width='140' height='140')
h2=`${profile.login}`
p=`${profile.bio}`
p
a.btn.btn-secondary(href=`/${profile.login}` role='button') View details ยป

You are sending the request in multiple chunks, node/express uses one request and one response.
Cannot set heads after they are sent to the client
Is the error that happens when the res.render is called the second time. At this point, the one request has already left the node/express process and this is tell you that you're trying to violate the one request/one response paradigm.
This is the part of your code where you can see why this happens.
router.get("/", function (req, res, next) {
let dataarray = [];
let userData = db.collection("user").find().limit(5).sort({
"created_at": -1
});
userData.each(function (err, doc) {
This part of your code will try to send a response for each item in your resultset.
Something like this will work properly (I didn't test it):
router.get("/", function (req, res, next) {
db.collection("user").find().limit(5).sort({ "created_at": -1 }, function(err, userData){
res.render("main", {
dataarray: userData,
_user: req.user
})
});
});
In other words, only one res.render is required and pass the entire result set into that.

Related

Route serve both param and request body nodejs

I have question about route to get both request from param and body
My route is to delete user. It looks like this:
router.delete("/delete/:id",middleware, async (req, res) => {
//firstly, I get param:
var userId = req.params.id || '';
//if emty, it will get request from body
if(!userId){
const listId = req.userIds
}
});
I perform request but it shows error: Cannot DELETE /api/users/delete
http://localhost:5000/api/users/delete/
Can you explain me what wrong with my issue?
Based on your latest comment you will need a route for collection delete as well as the model route. Here is some "pseudocode":
// model form
router.delete("/delete/:id",middleware, async (req, res) => {
var userId = req.params.id
// made up backend service - add error handling, etc
await dataService.users.delete(userId);
res.sendStatus(200); // again with error stuff
});
// collection form
router.delete("/delete",middleware, async (req, res) => {
var userIds = req.body.userIds; // assumes use of bodyParser
for (userId in userIds) {
// made up backend service - add error handling, etc
await dataService.users.delete(userId);
res.sendStatus(200); // again with error stuff
}
});

How can I keep my data and use it after with node-postgres

My problem is very simple, I need to put my data taken from the database in a variable but I don't know how to keep the variable defined. At the end of the pool the data went out and left the variable not defined.
So I have tried to make a res.send to send the data to the next :
.post('/route', data ,function(req, res){
...
});
but I think this is not a good idea.
.post('/musicbrainz/research/', function(req, result, next){
var nomArtiste = req.body.recherche;
var query = "SELECT idartiste * FROM artiste);";
db.query(query, (err, res) => {
if (err) {
return next(err);
}
rows = res.rows;
});
})
.get('/musicbrainz/results/', rows, function(req, res){
const results = rows;
...
My variable rows are undefined when it exits the db.query function.

How to pass data between express routes?

I'm making an API call in a POST route but for some reason, I can't pass the JSON data through res.render in the POST route. So I'm thinking about passing the JSON object to GET route so I can render it to the right client page.
Heres my GET and POST routes:
router.get('/bookDetails', (req, res) => {
res.render('bookDetails');
});
router.post('/bookDetails', (req, res) => {
let ID = req.body.ID;
request('https://www.googleapis.com/books/v1/volumes/' + ID, (err, response, body) => {
if(!err && response.statusCode == 200){
let bookdata = JSON.parse(body);
res.render('bookDetails', {bookdata: bookdata});
}else{
console.log(err);
}
});
});
I can't read the bookdata in my bookDetails.ejs file? Is there another way pass this data to the page?
On semantic, it should be a GET router to display something about the ID resource.
router.get('/bookDetails/:id', (req, res) => {
let resource = await fetchResourceById
res.render('bookDetails', resource);
});
also, you can define a middleware function to reuse the fetchResource logic, as following:
function fetchResourceMiddleware(){
return function(req, res, next){
var id = req.query.id || req.body.id
if(id){
req.resource = await fetchResource(id)
}
next()
}
}
reuse the middleware function for GET and POST router:
function renderResource(req, res){
res.render('bookDetails', req.resource);
}
router.get('/bookDetails/:id', fetchResourceMiddleware(), renderResource)
router.post('/bookDetails', fetchResourceMiddleware(), renderResource)
hope helpful, good luck!
After post, your get method will run.
In the get method, you are not sending any data to ejs template, so it will not detect it.
You should redirect in post method, it is bad idea sometimes,

Not able to return proper response after insert

I'm using Node.js/Express.js to install data to my MySQL DB.
Inserting data works fine, but returning success / fail gives me an error.
TypeError: Cannot read property 'status' of undefined
This is my code:
var crud = {
newProject: function (req, res, callback) {
db.query('INSERT INTO projects SET ?', req.body, function(err, res) {
// This is where it fails
if(err){
return res.status(500).json({error: err});
} else {
return res.status(200).json({success: 'Insert row success'});
}
});
},
}
// Express routing
app.post('/project/*', crud.newProject);
What am I not getting right here?
Solution
So this is what I used to make it work (after changing 'res' to 'resp' as suggested):
if (err) throw err;
res.end(JSON.stringify({response: 'Success'}));
Your defining res twice. The express response object is getting overwritten by the data param in your node callback.
Try the following (see comment)
var crud = {
newProject: function (req, res, callback) {
// changed 'res' to 'resp' to avoid collision with Express' 'res' object
db.query('INSERT INTO projects SET ?', req.body, function(err, resp) { // here's your error
// This is where it fails
if(err){
return res.status(500).json({error: err});
} else {
return res.status(200).json({success: 'Insert row success'});
}
});
},
}
// Express routing
app.post('/project/*', crud.newProject);
If you define error-handling middleware functions after the last app.use() in your main configuration
app.use(function (err, req, res, next) {
res.status(500).send(err.message || 'Internal server error.')
})
You can use the next callback as a catchall error handler, so the above would then become
var crud = {
newProject: function (req, res, callback) {
db.query('INSERT INTO projects SET ?', req.body, function(err, resp) {
if (err) return callback(err);
return res.json({success: 'Insert row success'});
});
},
}
// Express routing
app.post('/project/*', crud.newProject);
res.json() by default should add a 200 Success code to the response header. Ideally you would want to inspect the resp data param from the node callback after checking the state of err to properly handle the response and proceed accordingly, especially if you are dealing with last evaluated records associated with a continuation token usually provided in the response which some DBALs and APIs do for you and some don't. Either way you will want to be sure additional recursion isn't necessary to fetch remaining records before responding successfully.
Looks like the res object is undefined as it is not returning any response after the insert. You may return a new object like:
return {
status: 200,
json: {success: 'Insert row success'}
}

How to send json from nodejs server to client js file using Express and MongoDB

I am new to Nodejs and Express and want to search some results from mongoDB and show it on client browser, i can find the values from the mongoDB query but not able to send it to client js file,
It says doc is not defined, any help will be appreciated.
***app.js(Server)***
var bodyParser = require("body-parser");
var express = require("express");
var app = express();
var port = "8001";
var mongo= require('mongodb');
var mongoClient=mongo.MongoClient;
app.use(bodyParser.json());
app.use(express.static('public'));
app.get('/home', function(req, res) {
res.sendFile(__dirname + "/public/views/index.html");
});
app.listen(port, function() {
console.log("Server running at:" + port);
})
app.post("/response", function(req, res) {
var t = req.body;
mongoClient.connect("mongodb://localhost:27017/query", function(err,db){
cursor =db.collection('response').find({"name1":t.text},{"name2":1, "_id":0});
cursor.each(function(err, doc) {
if (doc != null) {
console.log(doc);
}
});
})
res.send(doc);
});
***index.js(Client Side)***
$.ajax({
url: '/response',
type:"POST",
contentType:"application/json; charset=utf-8",
complete: function(data) {
console.log(data.responseText);
alert(data.responseText);
}
});
doc is a variable local to your closure and therefore not available when you call res.send(doc).
In addition to that, you are iterating over all of your documents. You need to choose which one to return.
I recommend something like this:
cursor = db.collection('response').find({"name1":t.text},{"name2":1, "_id":0});
cursor.each(function(err, doc) {
if (doc != null) {
console.log(doc);
return res.json(doc); // return the first document found
}
});
Also note:
you should sanitize your data before passing it into the query
you shouldn't connect to the database on each request, instead set up mongo in the application context
you should check err to see if mongo returned an error before trying to iterate the cursor
EDIT:
To be more specific, the whole block should look like this:
app.post("/response", function (req, res) {
var t = req.body;
mongoClient.connect("mongodb://localhost:27017/query", function (err, db) {
if (err) {
return res.json(err);
}
db.collection('tweets').findOne({"name1": t.text}, {"name2": 1, "_id": 0}, function (err, doc) {
if (doc != null) {
console.log(doc);
return res.json(doc);
}
return res.sendStatus(404);
});
});
});
A few things:
cursor.each() has been deprecated in favour of cursor.forEach() assuming you're running a recent version of mongo
Your first line in a callback should be something like if (err) { console.error(err) } - at this point you'd probably see that your query is invalid:
Your query should probably look like .find({'name1': t.text, 'name2': 1, '_id': 0})
If you are referencing an auto-generated mongo ObjectID as _id, you have to use '_id': new mongo.ObjectID(<whatever string holds the _id>) in order for it to work. If you didn't specify an _id on creation, the automatically generated ObjectID will require this.
The mongo docs are great, highly recommend leafing through them for examples and which bits take which arguments and the options for all of them.
Consider using promises instead of callbacks to help tidy up. It's really easy with mongo - you just don't specify a callback function, and instead tack a .then(document => { ... }) on the end, and a single .catch(err => {console.error(err)}) will catch errors at the db, collection and cursor levels.
With jQuery, consider using .done(result => {...}) and .fail(err => { ... }) (aka promises) instead of complete for your ajax calls, and whatever you do, don't forget to attach an error handler. (I'm not even sure 'complete' is the right property, might depend on which jQuery you're using)
If you're doing an AJAX POST you should probably attach some data (and a dataType)to it. Otherwise you'll still get no records because req.body will be undefined or empty.
In the case of an error, you should be responding with res.status(500); res.end() at a minimum so you can tell when something has gone wrong on the server end.
To help along, console.log(req.body) right at the top of your function so you know what data is arriving.
Finally, if you intend on responding with JSON - use res.json(doc) instead of res.send(doc)

Categories

Resources