Send a JSON array as response from Node.js - javascript

I am fetching data from a MongoDB database then putting it in a cursor to send that as a Node.js response.
var router = express.Router();
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost/EmployeeDB';
/* GET users listing. */
router.get('/', function(req, res, next) {
//res.send('respond with a resource');
MongoClient.connect(url, function(err, db) {
var cursor = db.collection('Employee').find();
cursor.each(function(err, doc) {
console.log(doc);
arrayres = doc ;
res.send(doc);
});
db.close();
});
});
module.exports = router;
It sends only the first record then I get this error:
Error [ERR_HTTP_HEADERS_SENT]: Cannot remove headers after they are sent to the client
at ServerResponse.removeHeader (_http_outgoing.js:528:11)
at ServerResponse.send
Notice: I get this error only when there are multiple records to send as response.

You are sending the response twice. Which is impossible ( look at Why can't we do multiple response.send in Express.js? )
res.send('respond with a resource');
Here and
res.send(arrayres);
Here.
Here is a working example based on jeremy's answer :
router.get('/', function (req, res, next) {
MongoClient.connect(url, function (err, db) {
var cursor = db.collection('Employee').find();
let employees = []
const pushData = async () => {
cursor.forEeach( function (doc) {
employees.push(doc);
});
}
const sendResponse = async () => {
await pushData();
res.json(employees);
}
});
});

You can only send back one response to the browser (be it res.send(), res.end(), res.sendFile(), res.json() or any other). So, you can't have that inside a .forEach().
First, build an array, then send your data back once.
router.get('/', function (req, res, next) {
MongoClient.connect(url, function (err, db) {
var cursor = db.collection('Employee').find();
let employees = []
cursor.forEeach( function (doc) {
employees.push(doc);
});
res.json(employees);
});
});
Or with Mongoose :
Employee.find().lean().exec( (err,docs) => res.json(docs))

Related

How to get session variable in app.post request?

I would like to get the data from session variable (req.user.username) then use it for posting. I'm using passportjs as authentication. I'm using router. Here is my code:
router.use('/login', passport.authenticate("local-register", async (err, user, info) => {
if (err) {
return next('Error');
}
if (!user) {
return next('Error');
}
req.user = user;
return req.login(user, (error: Error) => {
if (error) {
return next('Error');
}
return req.session.save((erro: Error) => {
if (erro) {
return next('Error');
}
return next();
});
});
})(req, res, next);)
router.get('/', async (req, res) => {
console.log(req.user.username) // working just fine
});
router.post('/upload', async (req, res) => {
const uploaderName = req.user.username // I'm getting undefined
const upload = await database.query('INSERT INTO user WHERE username=$1', [uploaderName])
console.log(uploaderName);
})
So I finally found the answer to the question. For those who will encounter the problem in the future. You just add the session middleware AGAIN on the top of the routes. If your routes are separated to the main server file.
/src/routes/routes.ts -> add again the middleware on top.
const app = router();
app.use(sessions) // -> right here you need to add the middleware again to //access the req.user session variable
app.get('/', async (req, res) => {
console.log(req.user.username) // working just fine
});
app.post('/upload', async (req, res) => {
const uploaderName = req.user.username // I'm getting undefined
const upload = await database.query('INSERT INTO user WHERE username=$1', [uploaderName])
console.log(uploaderName);
})

how to create rest api using node.js express js and oracledb for update database

i am new to node.js and want to create api for getting data and update that data on frontend,please give me solution for this,i am getting data from this code but unable to update data.I am using react js for frontend.
var express = require("express");
var app = express();
var oracledb = require('oracledb');
var dbconfig= require('./dbconfig')
(async function () {
let connection
try {
connection = await oracledb.getConnection({
user: 'dbconfig.user',
password: 'dbconfig.password',
connectString: 'dbconfig.connectstring'
});
var result = await connection.execute('select * from
PROPERTY.app_booklet_challan_detail', []);
console.log("Successfully connected to Oracle!")
console.log(result)
} catch (err) {
console.log("Error: ", err);
} finally {
if (connection) {
try {
await connection.close()
} catch (err) {
console.log("Error when executing the database connection: ", err);
}
}
}
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
next();
});
app.get('/list', (req, res, next) => {
res.send(result);
next()
});
app.put('/list/update', (req, res, next) => {
let STATUS=res.data
connection.execute('UPDATE PROPERTY.app_booklet_challan_detail SET STATUS= ? WHERE
BOOKLETID= ? ', [STATUS])
res.send(STATUS)
next()
})
app.listen(3001, function () {
console.log("Started on PORT 3001");
})
})()
Your question is a little broad to answer with code, but I've written an entire series on this topic: https://jsao.io/2018/03/creating-a-rest-api-with-node-js-and-oracle-database/
Note there are links to a GitHub repo with the code from each module.
Once you finish with the series you should be able to take things in the direction that makes the most sense for your project.

Filtering MongoDB data in controller

I have this snippet of code in my controller but I'd like to filter the incoming records by a field archived == true in the MongoDB document.
Here is the filterless code that works right now. I'm not sure where to add the filter. I tried adding a simple filter() using prototype but it broke. What am I missing?
var Candidate = require('../models/candidate');
var async = require('async');
// Display list of all Candidate
exports.candidate_list = function(req, res, next) {
Candidate.find({}) //should something go in between the {}?
.sort([['name', 'ascending']])
.exec(function (err, list_candidates) {
if (err) { return next(err); }
//Successful, so render
res.render('candidate_list', { title: 'Candidates', list_candidates: list_candidates});
});
};
You can try this
var Candidate = require('../models/candidate');
var async = require('async');
// Display list of all Candidate
exports.candidate_list = function(req, res, next) {
Candidate.find({achived:true})
.sort([['name', 'ascending']])
.exec(function (err, list_candidates) {
if (err) { return next(err); }
//Successful, so render
res.render('candidate_list', { title: 'Candidates', list_candidates: list_candidates});
});
};

process.nextTick(function() { throw err; }); Error: Can't set headers after they are sent

I'm trying get data from MongoDB in a Node.js file.
I'm getting this error:
/home/jay/node_project/user_data_manag/node_modules/mongodb/lib/utils.js:98
process.nextTick(function() { throw err; });
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
at ServerResponse.header (/home/jay/node_project/user_data_manag/node_modules/express/lib/response.js:719:10)
at ServerResponse.json (/home/jay/node_project/user_data_manag/node_modules/express/lib/response.js:247:10)
at ServerResponse.send (/home/jay/node_project/user_data_manag/node_modules/express/lib/response.js:152:21)
at /home/jay/node_project/user_data_manag/routes/api.js:42:13
at /home/jay/node_project/user_data_manag/node_modules/mongodb/lib/cursor.js:777:7
at handleCallback (/home/jay/node_project/user_data_manag/node_modules/mongodb/lib/utils.js:96:12)
at /home/jay/node_project/user_data_manag/node_modules/mongodb/lib/cursor.js:741:16
at handleCallback (/home/jay/node_project/user_data_manag/node_modules/mongodb/lib/utils.js:96:12)
at /home/jay/node_project/user_data_manag/node_modules/mongodb/lib/cursor.js:675:5
// Dependencies
var express = require('express');
var router = express.Router();
var mongo = require('mongodb').MongoClient;
var objectId = require('mongodb').ObjectID;
var assert = require('assert');
var url = 'mongodb://localhost/rest_test';
router.post('/user', function(req, res, next) {
if (req.body.name == "Login") {
var result = [];
mongo.connect(url, function(err, db) {
var data = db.collection('products').find();
data.forEach(function(doc, err) {
result.push(doc);
}, function() {
db.close();
res.send({
iteamd: result
});
});
});
} else {
res.send("data");
}
res.end();
});
//insert data
router.post('/put-data', function(req, res, next) {
var item = {
title: req.body.name,
content: req.body.sku,
author: req.body.price
};
var data = req.body.name;
mongo.connect(url, function(err, db) {
var cursor = db.collection('products').find({
"name": data
});
res.send(cursor.toString);
});
});
// Return router
module.exports = router;
Don't call res.send() and res.end() in the same request handler.
res.send() will call res.end() for you (source). res.end() is typically used after calling multiple res.write().
If /user POST is called multiple times and the POST n doesn't close the connection with db.close(); before the n+1 POST you could get the same error.
Just solved on my script.

node.js/express chaining multiple get commands

I have a route I that in order to get all the data needs to access the API server multiple times (according to the data that was given).
Now I need to add a third access to the server and it's getting rather unreadable.
The following code is working, but I have a feeling I'm not doing it right (promises?) - couldn't figure out what exactly is recommended in this case
The code: (stripped down to emphasise the point)
router.get('/', function(req, main_response) {
http.get(FIRST_API_COMMAND, function (res) {
var moment_respose_content = '';
res.on("data", function (chunk) {
moment_respose_content += chunk;
});
res.on('end',function(){
if (res.statusCode < 200 || res.statusCode > 299) {
main_response.send('error in getting moment');
return;
}
var response = JSON.parse(moment_respose_content );
if (response.success)
{
var data = response.data;
//doing something with the data
http.get(SECOND_API_COMMAND, function (res) {
res.on("data", function (chunk) {
comment_respose_content += chunk;
});
res.on('end',function(){
var response = JSON.parse(comment_respose_content);
if (response.success)
{
var comments = response.data;
main_response.render('the page', {data: data});
return;
}
});
}).on('error', function (e) {
console.log("Got error: " + e.message);
main_response.send('Error in getting comments');
});
return;
}
});
}).on('error', function (e) {
console.log("Got error: " + e.message);
main_response.send('Error in getting moment');
});
});
You can write a middleware for each remote action, and then use those middlewares before the get handler, so the get handler can simply access their results. (Promises can help if you need to start subsequent requests before waiting for earlier ones to finish, but that situation is rare.)
For example, using express middleware to fetch each remote data independently:
var request = require('request');
var express = require('express');
var app = express();
var router = express.Router();
/* middleware to fetch moment. will only run for requests that `router` handles. */
router.use(function(req, res, next){
var api_url = 'https://google.com/';
request.get(api_url, function(err, response, body) {
if (err) {
return next(err);
}
req.moment_response = response.headers["date"];
next();
});
});
/* middleware to fetch comment after moment has been fetched */
router.use(function(req, res, next){
var api_url = 'https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain&rnd=new';
request.get(api_url, function(err, response, body){
if (err) {
return next(err);
}
req.comment_response = parseInt(body);
next();
});
});
/* main get handler: expects data to already be loaded */
router.get('/', function(req, res){
res.json({
moment: req.moment_response,
comment: req.comment_response
});
});
/* error handler: will run if any middleware called next() with an argument */
router.use(function(error, req, res, next){
res.status(500);
res.send("Error: " + error.toString());
});
app.use('/endpoint', router);
app.listen(8000);
Often the remote data you want to fetch is based on some parameter of the main request. In this case you would want to use req.param() instead of App.use() to define the data-loading middleware.

Categories