i wanted to create a fronted with a input type file for uploading data to my mongodb collection. I used the below code buts its giving me the following error
Error: ENOENT: no such file or directory, open 'C:\Users\User\cogazzimport\public\uploads\fcnewimport.csv'
My Codes
app.js
...
var storage = multer.diskStorage({
destination:(req,file,cb)=>{
cb(null,'./public/uploads');
},
filename:(req,file,cb)=>{
cb(null,file.originalname);
}
});
var uploads = multer({storage:storage});
//init app
var app = express();
//set the template engine
app.set('view engine','ejs');
//fetch data from the request
app.use(bodyParser.urlencoded({extended:false}));
//static folder
app.use(express.static(path.resolve(__dirname,'public')));
var temp ;
let url = "mongodb://localhost:27017/";
app.post('/',uploads.single('csv'),(req,res)=>{
csvtojson()
.fromFile(req.file.path)
.then(csvData => {
console.log(csvData);
mongodb.connect(
url,
{ useNewUrlParser: true, useUnifiedTopology: true },
(err, client) => {
if (err) throw err;
client
.db("coggaz")
.collection("idata")
.insertMany(csvData, (err, res) => {
if (err) throw err;
console.log(`Inserted: ${res.insertedCount} rows`);
client.close();
});
}
);
});
});
//assign port
var port = process.env.PORT || 3010;
app.listen(port,()=>console.log('server run at port '+port));
index.ejs
<form action="/" method="post" enctype="multipart/form-data">
<input type="file" name="csv"><br><br>
<div class="text-center"><button type="submit" class="btn btn-lg btn-primary">submit</button></div>
</form>
I tried various solutions but still getting the same error. Any solution with a correction code would be appreciated
use this code
var storage = multer.diskStorage({
destination:(req,file,cb)=>{
cb(null,'./public/uploads');
},
filename:(req,file,cb)=>{
cb(null,file.originalname);
}
});
var uploads = multer({storage:storage});
router.post('/import_data', uploads.single('file'), async (req, res) => {
try {
// importing csv file to database
const jsonArray = await csv().fromFile(req.file.path);
const roles = await Role.insertMany(jsonArray)
await roles.save()
res.send({msg:"csv data saved successfully"})
} catch (e) {
res.send(e)
}
use this and change Schema according to your databse name
Related
I'm a bit stuck with my blog app.
It works properly when I run it locally, but when it's deployed to Heroku it seems that the images that get uploaded via Multer aren't being uploaded into my images folder
When I create a post from the Heroku app, I can create the post - but the picture is missing
Below is my server code
const path = require("path");
const db = require('./config/connection');
const multer = require('multer')
const routes = require('./routes');
const app = express()
const PORT = process.env.PORT || 5000
app.use(express.urlencoded({ extended: true }));
app.use(express.json())
app.use("/images", express.static(path.join(__dirname, "./images")));
const storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, 'images')
},
filename: (req, file, callback) => {
callback(null, req.body.name)
}
})
const upload = multer({ storage: storage })
app.post('/upload', upload.single('file'), (req, res) => {
res.status(200).json('File has been uploaded')
})
if (process.env.NODE_ENV === 'production') {
app.use(express.static("client/build"));
}
app.use(routes)
db.once('open', () => {
app.listen(PORT, () => {
console.log(`API server running on port ${PORT}!`);
});
});
Below here is my client code
import React, { useContext, useState } from 'react';
import './write.css';
import { Context } from '../../context/Context';
export default function Write() {
const [title, setTitle] = useState('')
const [description, setDescription] = useState('')
const [file, setFile] = useState('')
const { user } = useContext(Context)
const handleSubmit = async (e) => {
e.preventDefault()
const newPost = {
username: user.username,
title,
description,
}
if(file){
const data = new FormData()
const filename = Date.now() + file.name
data.append('name', filename)
data.append('file', file)
newPost.postPicture = filename
try {
await axios.post('/upload', data)
} catch (error) {
console.log(error)
}
}
try {
const response = await axios.post('/posts', newPost)
window.location.replace('/posts/'+response.data._id)
} catch (error) {
console.log(error)
}
}
return (
<div className='write'>
{file &&
<img
className='write_image'
src={URL.createObjectURL(file)}
alt=""
/>
}
<form className='write_form' onSubmit={handleSubmit}>
<div className='write_form_group'>
<label htmlFor='file_input'>
<i className='write_icon far fa-plus-square'></i>
</label>
<input type='file' id='file_input' style={{display: 'none'}} onChange={e=>setFile(e.target.files[0])} />
<input type='text' placeholder='Title' className='write_input' onChange={e=>setTitle(e.target.value)}/>
</div>
<div className="write_form_group">
<textarea placeholder='Tell your story...' type='text' className='write_input write_text' onChange={e=>setDescription(e.target.value)}></textarea>
</div>
<button className='write_submit' type='submit'>Publish</button>
</form>
</div>
)
}
I'm not sure what's going wrong, my brain is being pointed into the server side code where I use multer.diskStorage (maybe this doesn't work when the app is being hosted somewhere?)
Any advice would be amazing
Also here is the link to the whole repo on my github... because I feel like just looking at the code in these posts might be hard to follow
https://github.com/Wickette/wickettes_blog
Heroku doesn't let you do this. You need to create a bucket on Amazon's S3 service or another similar service to upload that.
You may also use cloudinary its easy to use also a free service.
Hello there and Happy New Year to all:)
In the .ejs file there are two forms: one to get text inputs, another for file upload:
<div class="sectionContainer">
<div class="tour-upload">
<form method="post" action="/office/new-tour">
<label for="tourHeading">Tour Heading <em>*</em></label
><input
id="tourHeading"
name="tourHeading"
required=""
type="text"
placeholder="eg May 31-June 11 (Riga, Amsterdam, Riga)"
/>
<label for="tourDescription"
>Tour Info <em>*</em></label
>
<textarea
id="tourDescription"
name="tourDescription"
required=""
placeholder="Add tour details"
rows="4"
></textarea>
<button id="add-tour">Add Tour</button>
</form>
<form action="office/add-score" method="POST" enctype="multipart/form-data">
<div class="custom-file mb-3">
<input type="file" name="file" id="file" class="custom-file-input">
<label for="file" class="custom-file-label">Choose File</label>
</div>
<input type="submit" value="Submit" class="btn btn-primary btn-block">
</form>
</div>
In order to get get the info from the form where action="/office/new-tour", I can use this code in app.js:
Setup:
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const http = require("http");
const url = require("url");
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.set("view engine", "ejs");
And the actual code with logic:
app.get("/office", function (req, res) {
res.render("office");
});
//Mongo DB connection for form data saving
mongoose.connect("mongodb://localhost:27017/kbTourAppDB", {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const ToursSchema = {
tour: { tourHeading: String, tourDescription: String },
program: { tourProgram: String, tourProgramDescription: String },
};
const Tour = mongoose.model("Tour", ToursSchema);
app.post("/office/new-tour", (req, res) => {
const addedTour = new Tour({
tour: {
tourHeading: req.body.tourHeading,
tourDescription: req.body.tourDescription,
},
program: {
tourProgram: req.body.tourProgram,
tourProgramDescription: req.body.tourProgramDescription,
},
//add author when the login page is ready
});
addedTour.save(function (err) {
if (err) {
console.log("err: ", err);
} else {
console.log("sucess added new Tour to db");
}
});
res.redirect("/office");
});
app.listen(3000, function () {
console.log("listening on port 3000");
});
The code above works successfully for getting those text inputs to database, however I can't use it to upload the files to the database (mostly jpeg and pdf). For that I found a solution with Multer and GridFS.
Set up:
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const path = require("path");
const crypto = require("crypto");
const multer = require("multer");
const GridFsStorage = require("multer-gridfs-storage");
const Grid = require("gridfs-stream");
const methodOverride = require("method-override");
const http = require("http");
const url = require("url");
const app = express();
app.use(bodyParser.json());
app.use(methodOverride("_method"));
app.use(bodyParser.urlencoded({ extended: true }));
app.set("view engine", "ejs");
And code here:
app.get("/office", function (req, res) {
res.render("office");
});
const conn = mongoose.createConnection("mongodb://localhost:27017/kbTourAppDB");
let gfs;
conn.once("open", () => {
gfs = Grid(conn.db, mongoose.mongo);
gfs.collection("uploads");
});
//create storage object
const storage = new GridFsStorage({
url: "mongodb://localhost:27017/kbTourAppDB",
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if (err) {
return reject(err);
}
const filename = buf.toString("hex") + path.extname(file.originalname);
const originalFileName = file.originalname;
const fileInfo = {
filename: filename,
bucketName: "uploads",
};
resolve(fileInfo);
});
});
},
});
const upload = multer({ storage });
app.post("/office/add-score", upload.single("file"), (req, res) => {
res.redirect("/office");
});
app.listen(3000, function () {
console.log("listening on port 3000");
});
This code works for uploading files to database..
How can I write a code that will allow me to do both on the same page: upload the text input data to the MongoDB collection 'tour-data' for example, and the files from the other form to the collection 'uploads'..
Thank you very much for your help!
Actually when using multer, the text-fields from your form should still be populated under req.body.<field-name>, so you should be able to just use your initial code for inserting the tour-data:
app.post("/office/add-score", upload.single("file"), (req, res) => {
const addedTour = new Tour({
tour: {
tourHeading: req.body.tourHeading,
tourDescription: req.body.tourDescription,
},
program: {
tourProgram: req.body.tourProgram,
tourProgramDescription: req.body.tourProgramDescription,
}
});
addedTour.save(...)
});
I am making a small script to upload a photo and save it to local storage. I'm using Express and Muller for this.
I have an html page with an upload field (see below). As soon as I press the 'upload photo' button he sends the photo to the endpoint '/upload'. Here he should save the photo on my computer under the name 'image.jpg' only when it comes in the post the 'req.file' is empty.
I just wonder what is going wrong? Am I missing something?
App.js
const express = require("express");
const multer = require("multer");
const helpers = require("./helpers");
const app = express();
const port = process.env.PORT || 3000;
app.use(express.static(__dirname + "/"));
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads/");
},
filename: function (req, file, cb) {
cb(null, "image.jpg");
},
});
app.listen(port, () => console.log(`Listening on port ${port}...`));
app.post("/upload", (req, res) => {
let upload = multer({
storage: storage,
fileFilter: helpers.imageFilter,
}).single("image");
upload(req, res, function (err) {
if (req.fileValidationError) {
return res.send(req.fileValidationError);
} else if (!req.file) {
return res.send("Please select an image to upload");
} else if (err instanceof multer.MulterError) {
return res.send(err);
} else if (err) {
return res.send(err);
}
res.send(
`You have uploaded this image: <hr/><img src="${req.file.path}" width="500"><hr />Upload another image`
);
});
});
Helpers.js
const imageFilter = function(req, file, cb) {
// Accept images only
if (!file.originalname.match(/\.(jpg|JPG|jpeg|JPEG|png|PNG|gif|GIF)$/)) {
req.fileValidationError = 'Only image files are allowed!';
return cb(new Error('Only image files are allowed!'), false);
}
cb(null, true);
};
exports.imageFilter = imageFilter;
HTML Page
<form action="/upload" enctype="multipart/form-data" method="POST">
<input type="file" name="image" accept="image/*" />
<input type="submit" value="Upload Photo" />
</form>
It went wrong at the 'const storage'. I filled in the wrong file path. But it strange that the req.file was empty ... Anyway, it works!
I am having an issue in uploading the file to pc as well as DB at same time.
I am using two different Modules in my code
Multer: For uploading file from front-end to PC
CSV-to-JSON: For converting CSV File to json in order to store that file in Database.
But, using two separate functions isn't my intention at all.
So, when I tried combining both modules along with the base code, File uploading with Multer works but I want to upload that file to MongoDB which need to be solved by csv-to-json is a problem for me nothing seem's to be working.
here's is my code :
var express = require('express');
var multer = require('multer');
const csv = require('csvtojson');
// Import Mongodb
const mongoClient = require('mongodb').MongoClient,
assert = require('assert');
var filename = null;
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, 'uploads/')
},
filename: function(req, file, cb) {
filename = Date.now() + '-' + file.originalname;
cb(null, filename)
console.log(filename);
}
})
var upload = multer({
storage: storage
})
var app = express();
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
app.post('/', upload.single('file-to-upload'), function(req, res, next) {
// Mongodb Connection URL
const url = 'mongodb://localhost:27017/csvfilereader';
// Use connect method to connect to the Server
mongoClient.connect(url, (err, db) => {
assert.equal(null, err);
if (db) {
console.log("Connected correctly to server");
insertDocuments(db, function() {
db.close();
});
} else {
console.log('\n', 'Problem with connection', err)
}
});
const insertDocuments = (db, callback) => {
// Get the documents collection
let collection = db.collection('uploaded');
// CSV File Path
const csvFilePath = 'uploads/' + filename;
console.log(csvFilePath);
/**
* Read csv file and save every row of
* data on mongodb database
*/
csv()
.fromFile(csvFilePath)
.on('json', (jsonObj) => {
collection.insert(jsonObj, (err, result) => {
if (err) {
console.log(err);
} else {
console.log('suceess');
res.redirect('/');
filename = null;
}
});
})
.on('done', (error) => {
console.log('end')
})
}
});
app.listen(3200);
<!--
HTML Code that runs on Root
-->
<html lang="en">
<head>
<title>Simple Multer Upload Example</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form action="/" enctype="multipart/form-data" method="post">
<input type="file" name="file-to-upload">
<input type="submit" value="Upload">
</form>
</body>
</html>
You need to access the file name through the passed request from multer. Your filename variable doesn't point to any object.
req.file.filename will give access to your file that has been uploaded by multer.
UPDATED CODE:
var express = require("express");
var multer = require("multer");
const csv = require("csvtojson");
// Import Mongodb
const MongoClient = require("mongodb").MongoClient,
assert = require("assert");
var filename = null;
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, "uploads/");
},
filename: function(req, file, cb) {
filename = Date.now() + "-" + file.originalname;
cb(null, filename);
},
});
var upload = multer({
storage: storage,
});
var app = express();
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
app.post("/", upload.single("file-to-upload"), function(req, res, next) {
// Connection URL
const url = "mongodb://localhost:27017";
console.log("Multer", req.file.filename);
// Database Name
const dbName = "csvreader";
// Create a new MongoClient
const client = new MongoClient(url, { useNewUrlParser: true });
// Use connect method to connect to the Server
client.connect(function(err) {
assert.equal(null, err);
console.log("Connected successfully to database");
const db = client.db(dbName);
insertDocuments(db, function() {
console.log("Closing connection");
client.close();
});
});
const insertDocuments = (db, callback) => {
// Get the documents collection
const collection = db.collection("uploaded");
// CSV File Path
const csvFilePath = "uploads/" + filename;
console.log("Reading file from ", csvFilePath);
/**
* Read csv file and save every row of
* data on mongodb database
*/
csv()
.fromFile(csvFilePath)
.then(jsonObj => {
console.log(jsonObj);
collection.insert(jsonObj, (err, result) => {
if (err) {
console.log(err);
} else {
console.log("suceess");
res.redirect("/");
filename = null;
callback();
}
});
})
.catch(err => {
//error reading file
console.log(err);
});
};
});
app.listen(3200, () => {
console.log("Server working at port 3200");
});
I'm trying to capture a text-generated string (client / session based) for when a user is uploading an image.
Output when doing db.collection.find(); from console when uploading:
"_id" : ObjectId("590c67f472667e031fe80a9d"),
"path" : "uploads/bicycle.jpg",
"originalname" : "bicycle.jpg",
"__v" : 0
Here I want to have "imagelocation" : "N/A" also.
The string is based on a users location when uploading the image.
I want to connect that specific strings value to the image-objects ID as displayed above.
App.js:
/image UPLOAD TO MONGODB
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var path = require('path');
app.use(bodyParser.json());
//To get the access for the functions defined in imagefile.js class
var routes = require('./imagefile');
// connect to mongo,
mongoose.connect('mongodb://localhost:27017/gps');
app.use('/', routes);
// To get all the images/files stored in MongoDB
app.get('/images', function(req, res) {
routes.getImages(function(err, genres) {
if (err) {
throw err;
}
res.json(genres);
});
});
app.get('/images/:id', function(req, res) {
routes.getImageById(req.params.id, function(err, genres) {
if (err) {
throw err;
}
res.send(genres.path)
});
});
path and originalname are declared as follows in my imagefile.js:
var imageSchema = mongoose.Schema({
path: {
type: String,
required: true,
trim: true
},
originalname: {
type: String,
required: true
},
imagelocation:{ // format for storing
type: String,
required: true
}
});
module.exports = mongoose.model('Image', stringClass);
var Image = module.exports = mongoose.model('files', stringClass);
router.getImages = function(callback, limit) {
Image.find(callback).limit(limit);
}
router.getImageById = function(id, callback) {
Image.findById(id, callback);
}
router.addImage = function(image, callback) {
Image.create(image, callback);
}
//multer
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, 'uploads/')
},
filename: function(req, file, cb) {
cb(null, file.originalname);
},
imagelocation: function(req,file,cb){
cb(null, $('#coordinates').innerHTML);
}
});
var upload = multer({
storage: storage
});
router.get('/', function(req, res, next) {
res.render('layouts/main.handlebars');
});
router.post('/', upload.any(), function(req, res, next) {
res.send(req.files);
var path = req.files[0].path;
var imageName = req.files[0].originalname;
var imagepath = {};
imagepath['path'] = path;
imagepath['originalname'] = imageName;
router.addImage(imagepath, function(err) {
});
});
module.exports = router;
HTML:
<p id="coordinates">String is generated here</p>
TL;DR - how would i capture a string and send that along with the image when uploading it to my MongoDB?
To send a string a long with your image file, you just send it along with your form on submission. For instance in a hidden input field.
Then, on submission, you can access it as part of the req.body object
Here's an example (from an API, but you get the idea):
app.post('/api/file', function(req, res){
var upload = multer({
storage: storage
}).single('imageFile')
upload(req, res, function(err){
if(err){
// handle any errors here ...
}
console.log(req.body)// <-- here you can access your text string as 'req.body.yourStringIdentifier'
res.json({success: true, msg: 'File uploaded'});
})
})
If you have any questions feel free to ask :)
Edit: Full example
server.js:
const express = require('express');
const multer = require('multer');
const path = require('path');
const ejs = require('ejs');
var app = express();
app.set('view engine','ejs');
app.get('/', function(req, res){
res.render('index');
})
var storage = multer.diskStorage({
destination: function(req, file, callback){
callback(null, './uploads');
},
filename: function(req, file, callback){
callback(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
})
app.post('/', function(req, res){
var upload = multer({
storage: storage
}).single('imageFile')
upload(req, res, function(err){
console.log(req.body.textInput);
res.end('File is uploaded');
})
})
var port = process.env.PORT || 7850
app.listen(port, function(){
console.log('Listening on port ' + port);
})
index.ejs:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>INDEX</title>
</head>
<body>
<form id="uploadForm" enctype="multipart/form-data" method="post">
<input type="file" name="imageFile">
<input type="text" name="textInput">
<input type="submit" value="Upload file" name="submit">
</form>
</body>
</html>
This code works when I run it from the terminal with nodemon server.js. When the form is submitted, the contents of the text field is printed to the console.
Joel,
As per the Multer documentation, the Disk Storage
var storage = multer.diskStorage({.....})
engine gives you full control on storing files to disk and it has only two options available, destination and filename. They are both functions that determine where the file should be stored.
Destination is used to determine within which folder the uploaded files should be stored
Filename is used to determine what the file should be named inside the folder.
Hence your way of defining the multer.diskStorage is wrong.
If you are trying to upload it into MongoDB refer the following link:
https://ciphertrick.com/2017/02/28/file-upload-with-nodejs-and-gridfs-mongodb/
If you want to store the file in disk storage and then upload some information about the file that is stored using your schema
var imageSchema = mongoose.Schema({
path: {
type: String,
required: true,
trim: true
},
originalname: {
type: String,
required: true
},
imagelocation:{ // format for storing
type: String,
required: true
}
});
Then make changes in
var imagepath = {};
imagepath['path'] = path;
imagepath['originalname'] = imageName;
/* provide logic here as mentioned by David Stenstrøm to read it
from request.body and move it to the image schema object */
router.addImage(imagepath, function(err) {
});
Hope I clarified your query :) :)