I have an application where I need to read from two different collections in my Mongo database and pass both the returned objects into a handlebars template.
With the code I have below I can't figure out how to get it to work, as the universityData and courseData variables aren't getting populated, not sure if this is the right way to do it anyway.
The university and course objects in the callbacks are working correctly as when I log I get the values I need.
router.get('/newcastle/G400', function(req, res) {
var db = req.db;
var universityData;
var courseData;
db.collection('universities', function(err, collection) {
collection.findOne({'code': 'N21'}, function(err, university) {
universityData = university;
console.log(university);
//res.render('course', {title: university.name, university: university, course: { "code": "G400", "name": "Computer Science", "studylength": "3 years (BSc)/4 years (MSc)", "requirements": "AAB - ABB", "satisfactionrating": "98"}});
});
});
db.collection('courses', function(err, collection) {
collection.findOne({'universitycode': 'N21', 'code': 'G400'}, function(err, course) {
courseData = course;
console.log(course);
});
});
console.log(universityData);
console.log(courseData);
res.render('course', {university: universityData, course: courseData});
});
My question is how can I get the objects from each of the queries to be passed into one template?
Any help would be appreciated as I'm fairly new to Javascript, node and Mongo.
Even though it's just "two" functions, you could use a module like async to help organize them without deeply nesting. Example:
var async = require('async');
// ...
router.get('/newcastle/G400', function(req, res) {
var db = req.db;
async.parallel([
universityData: function(callback) {
db.collection('universities', function(err, collection) {
if (err)
return callback(err);
collection.findOne({'code': 'N21'}, callback);
});
},
courseData: function(callback) {
db.collection('courses', function(err, collection) {
if (err)
return callback(err);
collection.findOne({'universitycode': 'N21', 'code': 'G400'}, callback);
});
}
], function(err, results) {
if (err)
return res.send(500);
// results === { universityData: { ... }, courseData: { ... } }
res.render('course', results);
});
});
Related
I'm having an issue in trying to add the results of a query into an object. I am new to Node and Express so I apologize if I am making some stupid mistakes. I have been reading docs and watching videos pretty much non stop while I try to get this to work. Async is still wierd for my brain so I am sure I am doing things wrong, the function I placed seems wrong, I would appreciate so much any videos or articles you know of that could aid my comprehension as well haha!
Basically I have a table called stages, where the user can add or remove stages. I am pulling all the stages and then trying to add the projects that belong in those stages as an array of objects.
Ok so here is the code:
var myStages = []; //Global variable to hold stages.
//Get all the Stages
app.get('/', (req, res) => {
pool.getConnection((err, connection) => {
if(err) throw err;
console.log(`Connected as ID ${connection.threadId}`);
//Query
connection.query('SELECT * FROM solarcrm_stages', (err, rows) => {
connection.release();
if(!err) {
getProjects(rows);
} else {
console.log(err);
}
})
function getProjects(stages) {
myStages = stages;
Object.entries(myStages).forEach(entry => {
const[key] = entry;
connection.query('SELECT * FROM project WHERE iProjectStage = ?', [myStages[key]['iStageID']], (err, rows) => {
connection.release();
if(!err) {
myStages[key]['Projects'] = rows;
console.log(myStages); //Projects shows up as 'Projects: [ [TextRow] ]'
} else {
console.log(err);
}
});
});
}
})
})
The current result I get is this, Stage 1 has projects that should appear but shows [TextRow], Stage 2 should be empty as it is:
[
TextRow {
iStageID: 1,
sStageName: 'Stage1',
sStateIcon: 'null',
bActive: 1,
iOrderID: 1,
sStageDesc: null,
Projects: [ [TextRow] ]
},
TextRow {
iStageID: 2,
sStageName: 'Stage 2',
sStateIcon: 'null',
bActive: 1,
iOrderID: 2,
sStageDesc: null,
Projects: []
}
]
Thank you so much for any help or guidance you can offer.
Hi i am trying to use two selects in one JS file in node js and sql server. I am unable to figure out the syntax for this. I need a select to get all the persons from a table and another select to count the total number of persons in that table.Will it be possible to put those two selects in a single JS file. If so can someone help me with the syntax?
Here is the code i tried and i am getting the error
"cant Set headers after they are sent"
var sql = require("mssql");
var dbConfig = {
server: "XXXXX",
database: "XXXXX",
user: "XXXXX",
password: "XXXX",
port: 1433
};
exports.list = function(req, res){
sql.connect(dbConfig, function (err) {
if (err) console.log(err);
var request = new sql.Request();
request.query('select * from PERSON', function (err, recordset) {
if (err)
console.log(err)
else
console.log(recordset)
res.render('personinfo_itwx', { data: recordset });
});
request.query('select count(*) from PERSON', function (err, recordset) {
if (err)
console.log(err)
else
console.log(recordset1)
res.render('personinfo_itwx', { data: recordset1 });
});
});
};
#Aditya I'm not sure it's the best way to do so, although I would simply make two different requests, in order to achieve what you need. As I mentioned my in my comment, easiest way, would be to use (for instance) async library. And here's example you've asked for.
WARNING: I did not look at mysql docs
const async = require('async')
// {
async.series([
function(next)
{
new sql.Request()
.query('SELECT * from PERSON', next(err, resultList))
},
function(next)
{
new sql.Request()
.query('SELECT COUNT(*) from PERSON', next(err, count))
}
], (err, result) =>
{
/*
err: String
- if any of the shown above return an error - whole chain will be canceled.
result: Array
- if both requests will be succesfull - you'll end up with an array of results
---
Now you can render both results to your template at once
*/
})
// }
Surely, if you want manipulate with errors or results once you get them - you always may push error and results to new function, play with your data, and return the callback afterwards. Like so:
function(next)
{
new sql.Request()
.query('SELECT * from PERSON', (err, resultList) =>
{
if (err)
{
return next(err, null)
}
/*
data manipulation
*/
return next(null, resultList)
})
},
So I am trying to update the field status in my Report document and in my Station.reports sub-document which is an array of objects, in one single API call. The issue is that I am able to update the Report document, but not the station document when making the API call. After the call, the console.log(station.reports); returns the expected subdocument which is : [{"_id":"588fed278b50cd180bd6cc15","date":"2017-01-31T01:48:57.487Z","status":"Archived"}] But this is not saved in the corresponding Station document in my DB. Please I need help here. Thanks.
Station Document:
{
"_id": "588a777d4e26720e7afa7e1e",
"phone": "(007) – 007 – 7007",
"name": "name1",
"email": "name1#email.com",
"reports": [
{
"status": "Submitted",
"date": "2014-01-31T01:48:57.487Z",
"_id": "588fed278b50cd180bd6cc15"
}
]
}
Report Document
{
"_id": "588fed278b50cd180bd6cc15",
"description": "Description of the report",
"time": "05:48 PM",
"date": "2017-01-31T01:48:57.487Z",
"status": "Archived",
"location" : "123 Main Street"
"station" : "588a777d4e26720e7afa7e1e"
}
API Call
router.put('/reports/:id/updateStatus', function (req, res) {
Report.findById(req.params.id, function(err,report){
// if there is an error retrieving, send the error.
// nothing after res.send(err) will execute
if (err)
return res.send(err);
// Update the Report object
report.status = req.body.status;
// Update the Corresponding station.reports subdocument
Station.findOne({_id:report.station}, function (err, data) {
if(err) return console.log(err);
data.reports.forEach(function(rpt){
if (rpt._id == req.params.id){
rpt.status = req.body.status
data.save(function (err, station) {
if (err)
return res.send(err);
console.log(station.reports);
})
}
})
})
report.save(function (err, report) {
if (err)
return res.send(err);
res.json(report);
})
});
})
You are doing mistake while updating the station object. Use findOneAndUpdate to find the matching Station document, and then change the status of the matched reports item(matched using reports._id).
Try this:
Station.findOneAndUpdate({
_id:report.station,"reports._id":req.params.id
},{
$set : {reports.$.status : req.body.status}
},function(err){
if(err)
return res.send(err);
});
report._id will find the array element whose _id is req.params.id and report.$.status will update only the matching element of the array.
For more information on positional $(update) operator, Read mongoDB positional Documentation.
Also, i would suggest to save the report object in the callback of update. As nodejs is asynchronous, it will not wait for the update to finish, if you are saving report outside of the callback. And, you might get Cant set the headers after they are sent error. Thus, its recommended to do it in the callback.
Thus your final API code would look like:
router.put('/reports/:id/updateStatus', function (req, res) {
Report.findById(req.params.id, function(err,report){
// if there is an error retrieving, send the error.
// nothing after res.send(err) will execute
if (err)
return res.send(err);
// Update the Report object
report.status = req.body.status;
// Update the Corresponding station.reports subdocument
Station.findOneAndUpdate({
"_id":report.station,"reports._id":req.params.id
},{
$set : {"reports.$.status" : req.body.status}
},function(err, result){
if(err)
return res.send(err);
console.log(result);
report.save(function (err, report) {
if (err)
return res.send(err);
res.json(report);
});
});
});
})
UPDATE
Alternate Method
Another way can be, You can proceed in the original way, but don't save the data inside the forEach, instead save the data sheet forEach finishes.
Station.findOne({_id:report.station}, function (err, data) {
if(err) return console.log(err);
data.reports.forEach(function(rpt){
if (rpt._id == req.params.id){
rpt.status = req.body.status
}
});
data.save(function (err, station) {
if (err)
return res.send(err);
console.log(station.reports);
report.save(function (err, report) {
if (err)
return res.send(err);
res.json(report);
});
})
})
Hope this helps!
After multiple attempts, and with the help of Ravi, I was able to figure out a solution that worked for me pretty well. The only thing that changed was my API call. The rest of the code was unchanged.
Hope this helps someone having similar needs.
API CALL
router.put('/reports/:id/updateStatus', function (req, res) {
Report.findById(req.params.id, function(err,report){
// if there is an error retrieving, send the error.
// nothing after res.send(err) will execute
if (err)
return res.send(err);
// Update the Report object
report.status = req.body.status;
// Update the Corresponding station.reports subdocument
Station.findOne({_id:report.station}, function (err, info) {
if(err) return console.log(err);
info.reports.forEach(function(rpt){
if (rpt._id == req.params.id){
Station.update({_id:info._id, "reports._id":rpt._id },
{
$set:{"reports.$.status": req.body.status }
},function (err, results) {
if(err) return console.log("This Station couldn't be updated " + err);
console.log(results)
}
)
}
})
report.save(function (err, report) {
if (err)
return res.send(err);
res.json({report:report, station:info});
});
})
});
})
I have a Node.js app that is updating data in a MongoDB database using Mongoose.
I have setup the Mongoose model and I am able to successfully use the model.find, and model.remove functions, but I can't get the model.update function to work.
Can anyone help me?
/* ------------------------ Finding/Querying works ----------------------
Flot.find({ "label": "Trips Per Day"}, function (err, docs) {
res.jsonp(docs || err);
});
*/
/* ------------------------ Removing works -----------------------
Flot.remove({ "label": "Trips Per Client" }, function (err) {
if (err) return handleError(err);
res.json(err || "removed");
});
*/
var conditions = { "label": "Average Tons per Delivery" };
var update = { "label": "Average Tons per Delivery 2" };
var options = { };
var callback = function callback(err, numberAffected, rawResponse) {
if (err) return handleError(err);
console.log('Error: ', err);
console.log('NumberAffected: ', numberAffected);
console.log('RawResponse: ', rawResponse);
res.json(err || rawResponse || numberAffected );
};
Gage.update( conditions, update, options, callback );
I was able to get this working with node-mongodb-native. I'm still not sure why Mongoose wasn't working, but at least I got something to work.
var query = {"label": "Average Tons per Delivery"};
var update = {"type": "vertical"};
var options = {};
MongoClient.connect('mongodb://localhost/db', function(err, db) {
if(err) throw err;
db.collection('justgage').findAndModify(
query,
[['_id','asc']],
{$set: update},
options,
function(err, object) {
res.jsonp("Ok");
});
});
I'm developing a express.js application, without mongoose.
What I'm trying to do is, to encapsulate calls to mongodb inside a function, pass the function some parameter and get the data back from mongodb.
The problem I'm running into is explained by the code below
function get_data()
{
var mongo = require('mongodb'),Server = mongo.Server,Db = mongo.Db;
var server = new Server('localhost', 27017, {auto_reconnect: true});
var db = new Db('test', server);
db.collection('test_collection', function(err, collection) {
collection.find().toArray(function(err, items) {
var data = items;
});
});
console.log(data);
console.log("in get");
return data;
}
How do I return the items Array I pulled from mongo db from this function.
I want to know how scoping works in javascript and how do I put the items in a variable and return them from the get_data function.
After the answer
I fixed the code. It now works and looks like this.
function get_data(callback) {
var mongo = require('mongodb'),Server = mongo.Server,Db = mongo.Db;
var server = new Server('localhost', 27017, {auto_reconnect: true});
var db = new Db('test', server);
db.open(function(err, db) {
if (err) return callback(err);
db.collection('test_collection', function(err, collection) {
if (err) return callback(err);
collection.find().toArray(callback);
});
});
}
get_data(function(err, items) {
// handle error
console.log(items);
});
Since the items are retrieved from MongoDB asynchronously, the function get_data needs to accept a callback that will be used to return the results. I believe you'll also need to explicitly open the database connection.
function get_data(callback) {
...
db.open(function(err, db) {
if (err) return callback(err);
db.collection('test_collection', function(err, collection) {
if (err) return callback(err);
collection.find().toArray(callback);
});
});
}
get_data(function(err, items) {
// handle error
console.log(items);
});