Express JS + Multer query database before file upload - javascript

I'm using Node.JS + Express.JS + Multer to handle file uploads. The problem is that I need to query the database to see if a file with this name has been uploaded in the past. If it hasn't been uploaded, then it should be accepted. Otherwise, the file should not be accepted. I'm trying to get this to work using the onFileUploadStart function; however, the database query is asynchronous and I see no way to return false given that the result of the query appears in a callback. If there is a way to execute the query synchronously, my goal will be easy to accomplish. Here is the code:
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
var connection = mysql.createConnection({
//connection details
});
router.post('/upload', multer({
onFileUploadStart: function(file, req, res) {
var queryString = "SELECT count(fileName) as count FROM table WHERE fileName = ?;",
queryInserts = [file.originalname];
queryString = mysql.format(queryString, queryInserts);
connection.query(queryString, function(err, rows) {
if (err) {
// handle error
} else {
if (rows[0].count > 0) {
// file should not be accepted
} else {
// file should be accepted
}
}
});
},
dest: "./uploads/"
}), function(req, res) {
// do other stuff
});
Any ideas of how I can accomplish this will be greatly appreciated. Thanks.

My quick reaction would be to use promises. You could have your onFileUploadStart handler create a deferred, assign its promise to the active request object and handle the resolution or rejection of the promise. Then in the main handler for the upload route, you could use then.
I believe this would basically be the new code as applied to your current code. I Note that I am using the Q promises library, but there are other options (promises are also built into ES6 if you are using it).
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
var Q = requires('q');
var connection = mysql.createConnection({
//connection details
});
router.post('/upload', multer({
onFileUploadStart: function(file, req, res) {
var deferred = Q.defer();
req.fileUploadPromise = deferred.promise;
var queryString = "SELECT count(fileName) as count FROM table WHERE fileName = ?;",
queryInserts = [file.originalname];
queryString = mysql.format(queryString, queryInserts);
connection.query(queryString, function(err, rows) {
if (err) {
// handle error
deferred.reject('You had an error...');
} else {
if (rows[0].count > 0) {
// file should not be accepted
deferred.reject('You had a duplicate file');
} else {
deferred.resolve(file); // ?? or something useful
// file should be accepted
}
}
});
},
dest: "./uploads/"
}), function(req, res) {
req.fileUploadPromise
.then(function(successResult){
// do other stuff
res.status(200).send('success');
})
.catch(function(errorResult){
// read the error result to provide correct code & error message for user
})
.done();
});

Related

Having some problems trying to call a function from another script

I'm building a mockup website to try and learn NodeJS. I want a login system and I'm trying to connect my register page with my database script. The sql function that sends queries to the database is working as intended, however, when trying to call the query function from the script that manages the register webpage all I get is an error 500.
It would be cool if someone could point me in the right direction, surely it's some quirk from NodeJS I don't know about yet.
Here is my register page script that should call the query function from POST routing:
var express = require('express');
var router = express.Router();
var db = require('../public/javascripts/dbController');
router
.get('/', function(req, res, next) {
res.render('register.html', {title: 'Register'})
})
.post('/', function(req, res, next) {
register(req.body);
res.render('register.html', {title: 'Register'})
})
function register(request)
{
let username = request.login;
let password = request.password;
let sql = "INSERT INTO users (user_username, user_password, user_status) VALUES ('"+username+"','"+password+"', 1);";
console.log("query");
//Why is this not working?
db.query(sql);
}
module.exports = router;
And here is (part of) my dbController script:
const sqlite3 = require('sqlite3').verbose();
let db = new sqlite3.Database('./public/database/db.db', sqlite3.OPEN_READWRITE, (err) => {
if (err && err.code == "SQLITE_CANTOPEN") {
createDatabase();
return;
} else if (err) {
console.log("Getting error " + err);
exit(1);
}
});
//This function is not running when I ask for it in register.js
function query(sql){
console.log("running query: " + sql)
db.all(sql, [], (err, rows) => {
if (err) {
throw err;
}
rows.forEach((row) => {
console.log(row.name);
});
});
}
module.exports = query;
I figure that I probably have to route my scripts through the main app script or maybe I'm exporting wrong? Anyway, any nudge in the right direction would be great because I've been stuck on it a few days. Thanks!
For what I can see, you're indeed importing the "query" function into your "register" page. But you're setting a name of "db" to it.
var db = require('../public/javascripts/dbController');
but you're not exporting "db" you're exporting "query":
module.exports = query;
But that's not really the issue, you could just call it "myRandomNameImport" and it would still work. The problem is that you're accessing a property of "db" that does not exist.
db.query(sql); /* <- db.query does not exist.
* Try db(sql) instead. */
"db" does not have any properties called "query", the function you're trying to use is "db".
function register(request) {
let username = request.login;
let password = request.password;
let sql = "INSERT INTO users (user_username, user_password, user_status) VALUES ('"+username+"','"+password+"', 1);";
console.log("query");
db(sql); /*<- Just call db()*/
}

My mongodb return the array empty []

I'm studying a build full stack JavaScript apps with the MEAN stack, using Node.js, AngularJS, Express and MongoDB.
I'm in the third section where I have to retrieve all the hotels in my database.
When in the browser I type http: // localhost: 3000 / api / hotels /, my database returns an empty array, but the hotel.data.json file is full.
I also tried a copied section5's teacher's final work, but I have the same result, my database is empty [].
This is the code of the hotels.controllers file:
var mongoose = require('mongoose');
var Hotel = mongoose.model('Hotel');
module.exports.hotelsGetAll = function(req, res) {
console.log('GET the hotels');
console.log(req.query);
var offset = 0;
var count = 5;
if (req.query && req.query.offset) {
offset = parseInt(req.query.offset, 10);
}
if (req.query && req.query.count) {
count = parseInt(req.query.count, 10);
}
Hotel
.find()
.skip(offset)
.limit(count)
.exec(function(err, hotels) {
console.log("Found hotels", hotels.length);
res
.json(hotels);
});
};
module.exports.hotelsGetOne = function(req, res) {
var id = req.params.hotelId;
console.log('GET hotelId', id);
Hotel
.findById(id)
.exec(function(err, doc) {
res
.status(200)
.json(doc);
});
};
module.exports.hotelsAddOne = function(req, res) {
console.log("POST new hotel");
var db = dbconn.get();
var collection = db.collection('hotels');
var newHotel;
if (req.body && req.body.name && req.body.stars) {
newHotel = req.body;
newHotel.stars = parseInt(req.body.stars, 10);
collection.insertOne(newHotel, function(err, response) {
console.log("Hotel added", response);
console.log("Hotel added", response.ops);
res
.status(201)
.json(response.ops);
});
// console.log(newHotel);
// res
// .status(200)
// .json(newHotel);
} else {
console.log("Data missing from body");
res
.status(400)
.json({
message: "Required data missing from body"
});
}
};
Thanks for the reply.
This is the file of routes:
var express = require('express');
var router = express.Router();
var ctrlHotels = require('../controllers/hotels.controllers.js');
// Hotel routes
router
.route('/hotels')
.get(ctrlHotels.hotelsGetAll);
router
.route('/hotels/:hotelId')
.get(ctrlHotels.hotelsGetOne);
router
.route('/hotels/new')
.post(ctrlHotels.hotelsAddOne);
module.exports = router;
My console.log() tell:
GET /api/hotels
Requested by: undefined
GET the hotels
{}
(node:2780) DeprecationWarning: Mongoose: mpromise (mongoose's default promise library) is deprecated, plug in your own promise library ins
null
[]
Found hotels 0
I have a hothel-data.json file with all the hotels, the professor in the video at the command prompt when he connects to the db type mongod, but he gave me an error, so when I plug in the db type: mongod --dbpath = data.
I have a main folder, inside I have an API folder with 3 folders inside.
1 CONTROLLERS folder, with hotels-controllers.js, 2 DATA folder with db.js, dbconnection.js, hotel-data.json, hotels.model.js, and 3 ROUTES folder with index.js.
I solved importing the hotel-data.json file, now it's ok, when typing ocalhost: 3000 / api / hotels I see all the hotels.
Thanks anyway.
Aurora

express routes do not load again

I'm encountering a problem with the express routes. Here's my case:
I have a node js app with the following code in app.js
var express = require('express');
var app = express();
var path = require('path');
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended: false
}));
var cfenv = require('cfenv');
// request module provides a simple way to create HTTP requests in Node.js
var request = require('request');
var routes = require('./routes')(app);
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname + '/public/index.html'));
});
var appEnv = cfenv.getAppEnv();
// compose for mysql code
var dbcontroller = require('./controller/compose-mysql-connection');
dbcontroller.databaseconnection();
const util = require('util');
// and so is assert
const assert = require('assert');
var mysql = require('mysql');
var appEnv = cfenv.getAppEnv();
// Within the application environment (appenv) there's a services object
var services = appEnv.services;
// The services object is a map named by service so we extract the one for Compose for MySQL
var mysql_services = services["compose-for-mysql"];
// This check ensures there is a services for MySQL databases
assert(!util.isUndefined(mysql_services), "Must be bound to compose-for-mysql services");
// We now take the first bound Compose for MySQL database service and extract it's credentials object
var credentials = mysql_services[0].credentials;
var connectionString = credentials.uri;
// set up a new connection using our config details
var connection = mysql.createConnection(credentials.uri);
//reading from the database
app.get("/read_fb_info", function(request, response) {
connection.query('SELECT * FROM fb_info_table ORDER BY name ASC', function (err, result) {
if (err) {
console.log(err);
response.status(500).send(err);
} else {
console.log(result);
response.send(result);
}
});
});
app.use(express.static(__dirname + '/public'));
// start server on the specified port and binding host
app.listen(appEnv.port, '0.0.0.0', function() {
// print a message when the server starts listening
console.log("server starting on " + appEnv.url);
});
Then, in the routes folder I have a file with other two routes I use into the application.
Once the index page is loaded I have two button:
<body>
<div class="container">
<h1>External API Usage</h1>
<h3>LinkedIn</h3>
<a href='/info/linkedin'>
<img src="/images/LinkedIn_image.png" class="img-rounded" alt="LinkedIn" width="150" height="150">
</a>
<h3>Facebook</h3>
<a href='/info/facebook'>
<img src="/images/Facebook_image.png" class="img-rounded" alt="Facebook" width="150" height="150">
</a>
</div>
To handle routes I created an index.js file in the routes folder which includes the following:
retrieveFacebookUserInfo = function() {
var deferred = Q.defer();
var propertiesObject_FB = { id:'id', name:'name', access_token:'access_token' };
request({url:'https://graph.facebook.com/', qs:propertiesObject_FB}, function(err, response, body) {
if(err) {
deferred.resolve(null);
}
else {
var fb_json = JSON.parse(body);
console.log("Get response: " + response.statusCode);
console.log(fb_json);
//storing information to db
dbcontroller.writingtodb();
deferred.resolve(fb_json);
}
});
return deferred.promise;
};
app.get('/info/facebook', function(req, res){
retrieveFacebookUserInfo().then(function(result){
res.render('facebook.ejs', {
title : 'Facebook information',
fb_obj: result
});
});
});
app.get('/info/linkedin', function(req, res){
retrieveLinkedInUserInfo().then(function(result){
res.render('linkedin.ejs', {
title : 'LinkedIn information',
headline_linkedin: result.headline
});
});
});
If I try to open the second one (/info/facebook) at first e then the first one (/info/linkedin) it doesn't load the page related of /info/linkedin route. It shows this message:
404 Not Found: Requested route ('linkedin-demo-app.eu-gb.mybluemix.net') does not exist.
Do you guys know what is this kind of problem? It seems like it doesn' recognize and find the route again.
Thanks in advance
You simply don't have route handler for these two paths. You need to create them like you did for your /read_fb_info path:
app.get("/info/linkedin", function(request, response) {
//do somenthing and send your response
});
app.get("/info/facebook", function(request, response) {
//do somenthing and send your response
});

How to update and read a collection in MongoDB using Mongoose

I am having trouble with a project I am working on. I want to create a database in which I can store dates and links to YouTube videos in a MongoDB database. I am using Mongoose as the ORM. The problem seems to be that the database and collection is created and I can read and update it outside the routes but not inside (if anyone can understand what I am saying). I want to be able to make a GET request for the current items in the database on the /database route as well as make a POST to the /database route.
My code is below. Please help:
//grab express and Mongoose
var express = require('express');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//create an express app
var app = express();
app.use(express.static('/public/css', {"root": __dirname}));
//create a database
mongoose.connect('mongodb://localhost/__dirname/data');
//connect to the data store on the set up the database
var db = mongoose.connection;
//Create a model which connects to the schema and entries collection in the __dirname database
var Entry = mongoose.model("Entry", new Schema({date: 'date', link: 'string'}), "entries");
mongoose.connection.on("open", function() {
console.log("mongodb is connected!");
});
//start the server on the port 8080
app.listen(8080);
//The routes
//The route for getting data for the database
app.get("/database", function(req, res) {
Entry.find({}, function(err, data) {console.log(err, data, data.length); });
});
//The route for posting data on the database
app.post("/database", function(req, res) {
//test new post
var newMonth = new Entry({date: '1997-10-30', link: 'https://wwww.youtube.com/'});
newMonth.save(function(err) {
if (err !== null) {
//object was not save
console.log(err);
} else {
console.log("it was saved!")
};
});
});
//create an express route for the home page at http://localhost:8080/
app.get('/', function(req, res) {
res.send('ok');
res.sendFile('/views/index.html', {"root": __dirname + ''});
});
//Send a message to the console
console.log('The server has started');
Your GET request should have worked because a browser executes a GET request by default. Try the following.
app.get("/database", function(req, res) {
Entry.find(function(err, data) {
if(err) {
console.log(err);
} else {
console.log(data);
}
});
});
As far as testing your POST route is concerned, install a plugin for Google Chrome called Postman. You can execute all sorts of requests using it. It's great for testing purposes.

Node.js Making a Variable Wait to be Assigned Until Callback Function is Done

I am using Node.js, Express, MongoDB, and Mongoose. I have a function that fetches the largest id number of a document in my MongoDB database and returns it to the program. I have begun modularizing my code, and have migrated that function to another module. I have successfully accessed the function in my main module, but it involves an asynchronous database query. As the function returns a value, I want to assign it to a variable. Unfortunately, When the returned value is assigned to the variable, the variable is actually set to undefined. I was thinking about using event emitters to signal that the query is finished, but that presents two issues as well:
1) I don't think you can do anything in a program AFTER a return statement, which would be what is required.
2) Event Emitters between modules seem very finicky.
Please help me get the variable to be assigned to the correct value. Code for both the main function and the module is below:
(main file) app.js:
//requires and start up app
var express = require('express');
var mongoose = require('mongoose')
, dbURI = 'localhost/test';
var app = express();
var postmodel = require('./models/post').postmodel;
//configures app for general stuff needed such as bodyParser and static file directory
app.configure(function () {
app.use(express.bodyParser());
app.use(express.static(__dirname + '/static'));
});
//configures app for production, connects to mongoLab databse rather than localhost
app.configure('production', function () {
dbURI = 'mongodb://brad.ross.35:lockirlornie#ds037387.mongolab.com:37387/heroku_app6901832';
});
//tries to connect to database.
mongoose.connect(dbURI);
//once connection to database is open, then rest of app runs
mongoose.connection.on('open', function () {
var PostModel = new postmodel();
var Post = PostModel.setupPostSchema();
var largest_id = PostModel.findLargestID(Post);
(module) post.js:
var mongoose = require('mongoose');
module.exports.postmodel = function () {
this.setupPostSchema = function () {
var postSchema = new mongoose.Schema({
title: String,
body: String,
id: Number,
date_created: String
});
var Post = mongoose.model('Post', postSchema);
return Post;
};
this.findLargestID = function (Post) {
Post.find(function (err, posts) {
if (err) {
console.log("error finding largest ID!");
} else {
var largest_id = 0;
for (var post in posts) {
if (posts[post].id >= largest_id) largest_id = posts[post].id;
}
console.log(largest_id);
return largest_id;
}
});
};
};
You need to have findLargestID accept a callback parameter that it will call once largest_id is available:
this.findLargestID = function (Post, callback) {
Post.find(function (err, posts) {
if (err) {
console.log("error finding largest ID!");
callback(err);
} else {
var largest_id = 0;
for (var post in posts) {
if (posts[post].id >= largest_id) largest_id = posts[post].id;
}
console.log(largest_id);
callback(null, largest_id);
}
});
};

Categories

Resources