express.js - Run python script on form-submit using POST & routing - javascript

I have installed python-shell per the instructions on this site and am able to get this code to run on test.ejs on page load:
var PythonShell = require('python-shell');
var options = {
scriptPath: '/nodeGit/scripts',
};
PythonShell.run('my_script.py', options, function (err) {
if (err) throw err;
console.log('finished');
});
I get this to run on test.ejs page load by putting it in test.js.
The portion of test.js regarding my test.ejs page looks like this:
exports.test = function(req, res,callback){
PythonShell.run('my_script.py', options, function (err, results) {
if (err) throw err;
// results is an array consisting of messages collected during execution
console.log('results: %j', results);
});
// The functions below were not written by me but were left in to show how functions are written(?) in hopes that it helps
async.auto({
getData: function get_data(callback){
Images.findAll({where: {uploaded: 1}})
.then(function(getData){
callback(null, getData);
})
.catch(function(err){
console.log("*******Did not return Image Info ********");
callback(err);
});
}
function done(err, results){
callback({
userList: results.getUser,
imageList : results.getData,
user: results.verifyUser,
});
});
}
Instead of running the script on page-load, I want to call it when I submit an HTML form (& pass in the form's parameters). How would I go about that?

Related

Trouble with callbacks, error catching and MongoDB

I've been working on an application which allows me to add companies to a database. Originally my code was pure spaghetti, so I wanted to modularize it properly. For this purpose, I added routes, a controller and a dao.
This is how my code looks right now
Routes
app.post('/loadcompanies', (req, res)=> {
companiesController.loadcompany(req.body, (results)=>{
console.log(results);
res.send(200, "working!");
})
})
Controller
module.exports.loadCompany = (body, callback)=>{
companiesDao.loadCompany(body, callback);
}
Dao
module.exports.loadCompany = (company, callback)=>{
MongoClient.connect(conexionString, (err, database) => {
if (err) console.log(err);
db = database;
console.log(company);
db.collection('companies').insert(company, (err, result)=>{
callback({message:"Succesfully loaded company", company:result});
});
})
}
My current concern is that working with errors when modularizing like this is confusing. I tried adding a try-catch method around the db insert and throwing and error if there is one, but that doesn't seem to work. Other things I've tried is returning the error in the callback, like this:
if (err) callback (err, null);
but I end up getting a "Can't set headers after they are sent." error.
How would you handle errors in this situation? For example, in the case that someone tries to add a duplicate entry in an unique element.
You should be able to simply do the error checking inside the callback for the insert function:
db.collection('companies').insert(company, (err, result)=>{
if (err) {
callback(err, null);
return;
}
callback(null, {message:"Succesfully loaded company", company:result});
});
If you get an error like you say, that's probably because the database is actually returning an error. You could also make your errors more specific, like:
module.exports.loadCompany = (company, callback)=>{
MongoClient.connect(conexionString, (err, database) => {
if (err) {
callback(new Error('Connection error: ' + err.Error());
return;
}
db = database;
console.log(company);
db.collection('companies').insert(company, (err, result)=>{
if (err) {
callback(new Error('Insertion error: ' + err.Error());
return;
}
callback(null, {message:"Succesfully loaded company", company:result});
});
})
Here is your loadCompany done in async / await format.
Notise there is no need for error checking, errors will propagate as expected up the promise chain.
Note I've also changed loadCompany to be an async function too, so to call it you can simply do var ret = await loadCompany(conpanyInfo)
module.exports.loadCompany = async (company)=>{
let db = await MongoClient.connect(conexionString);
console.log(company);
let result = await db.collection('companies').insert(company);
return {message:"Succesfully loaded company", company:result};
}

Async confusion in nodejs function

I always have multiple operations in one route or endpoint. Take an example below, when a user deletes an item, I want the related file be deleted in s3 too besides deleting related collection from the database.
So is the code below ok? Does it matter if I put the first function (delete file from s3) inside the DeleteItem function?
router.post('/item/delete', function(req, res) {
if(req.body.dlt_item){
var tempArray = [];
tempArray.push({"Key":req.body.dlt_item});
s3Bucket.deleteObjects({
Bucket: 'myS3',
Delete: {
Objects: req.body.dlt_item
}
}, function(err, data) {
if (err)
return console.log(err);
});
}
Item.DeleteItem(req.body.item_id, function(err,result){
if(err){console.log(err)}
res.send({result:1});
})
});
You should organise your code like this. This will ensure that s3 deletion will start only when mongodb deletion has finished.
In your code both things happen simultaneously. this may cause issue in some cases.
If one fails and other succeeds then there will be trouble. Suppose s3 files get deleted successfully and mongo deletion fails. Then you will have many references to non existing resources.
router.post('/item/delete', function(req, res) {
if(req.body.dlt_item){
var tempArray = [];
tempArray.push({"Key":req.body.dlt_item});
Item.DeleteItem(req.body.item_id, function(err,result){
if(err)
{
console.log(err)
res.send(err);
}
else
{
//deletion from mongodb is succesful now delete from s3
s3Bucket.deleteObjects({
Bucket: 'myS3',
Delete: {
Objects: req.body.dlt_item
}
},function(err, data) {
if (err)
{
// deletion from s3 failed you should handle this case
res.send({result:1});
return console.log(err);
}
else
{
// successful deletion from both s3 and mongo.
// If you do not want to wait for this then send the response before this function.
res.send({result:1});
}
});
}
})
});

How to find a document by an field other than _id using mongo/mongoose

Background:
I must create or update an document based on post request that I have zero control over. I'm calling the function updateOrCreate()
Question:
How can I properly find a document by an field called nuid without using _id in mongo/mongoose
example payload:
curl -H "Content-Type: application/json" -X POST -d '{"participant":{"nuid":"98ASDF988SDF89SDF89989SDF9898"}}' http://localhost:9000/api/things
thing.controller:
exports.updateOrCreate = function(req, res) {
//Thing.findByNuid() will not work but it will explain what i'm trying to accomplish
/**
Thing.findByNuid(req.body.participant.nuid, function (err, thing) {
if (err) { return handleError(res, err); }
if(!thing) {
Thing.create(req.body.participant, function(err, thing) {
if(err) { return handleError(res, err); }
});
}
var updated = _.merge(thing, req.body.participant);
updated.save(function (err) {
if (err) { return handleError(res, err); }
});
});
**/
//this block will fetch all the things that have nuids but that seems really heavy and awful practice
Thing.find({'nuid':req.body.participant.nuid}, function(err, thing){
console.log(thing);
});
// This block is here to communicate this will create a new thing as expected.
Thing.create(req.body.participant, function(err, thing) {
if(err) { return handleError(res, err); }
});
}
Schema
var ThingSchema = new Schema({
nuid: String
});
UPDATE:
var query = {"nuid": req.body.participant.nuid};
var update = {nuid: 'heyyy'};
Thing.findOneAndUpdate(
query,
update,
{upsert: true},
function(err, thing){
console.log(thing, "thing");
console.log(err, "err");
}
);
I would use findOneAndUpdate first and then based on the result do an insert. findOneAndUpdate use mongoDB findAndModify command.
You should also look at new & upsert options of it which would create a document if not found.

Request Multiple URL with Async

I am creating my first node app using ExpressJS and I am confused about how to requesting multiple url's using Request and async. The code I have below spits out the following error, "chart1 is not defined".
router.get('/', function(req, res) {
async.parallel([
function(next) {
apiRequestGoesHere(chart1, function(error) {
request.get('http://203.33.33.44:8080/reports/43?type=0&key=fakekey'),
next(null, firstData);
});
},
function(next) {
anotherApiRequest(chart2, function(error) {
request.get('http://203.33.33.44:8080/reports/42?type=0&key=fakekey'),
next(null, secondData);
});
}],
function(err, results, firstData, secondData) {
// results is [firstData, secondData]
res.render('index', {
title: 'Home KP',
firstData: chart1
});
});
});
Can someone please explain to me how to define these and get this working?
Your callback is not defining chart1 anywhere. Maybe you want to check results[0]?
With async.parallel, the results variable contains the results of all the functions, in the same order. When you call next(null, firstData), you're telling async to put the value of firstData into the results array, and since that function is the first, it will go into results[0] (next one is results[1], etc).

Writing MongoDB result to file using native Node.js driver

I am trying to write the results of a MongoDB query to a file using the native Node.js driver. My code is the following (based on this post: Writing files in Node.js):
var query = require('./queries.js');
var fs = require('fs');
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect("mongodb://localhost:27017/test", function(err, db) {
if(err) { return console.dir(err); }
var buildsColl = db.collection('blah');
collection.aggregate(query.test, function(err, result) {
var JSONResult = JSON.stringify(result);
//console.log(JSONResult);
fs.writeFile("test.json", JSONResult, function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved!");
}
});
});
collection.aggregate(query.next, function(err, result) {
var JSONResult = JSON.stringify(result);
//console.log(JSONResult);
db.close();
});
});
The file is written, but the contents are 'undefined.' Printing the result to the console works though.
Your code is not checking the err on the aggregate callback.
You are likely getting an Mongo error and the result is undefined in that case...
Other thing I could suspect is that you are getting multiple callbacks -- each one of them creates a new files, erasing the content.
Try using fs.appendFile instead of fs.writeFile and see if you are getting the expected data (plus the unwanted undefined)
For anyone stumbling across this the solution on where to put the db.close() is below:
collection.aggregate(query.test, function(err, result) {
var JSONResult = JSON.stringify(result);
//console.log(JSONResult);
fs.writeFile("test.json", JSONResult, function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved!");
}
});
collection.aggregate(query.next, function(err, result) {
var JSONResult = JSON.stringify(result);
//console.log(JSONResult);
db.close();
});
});

Categories

Resources