Uploading an image to mongodb using Multer with Express and Axios - mongodb

I am basically trying to make a small application which allows an admin user to enter a name, price and image of a product which can then be viewed on another page. The details will be sent to a mongo database which will be performed via an axios post from the front end. I can send the name and the price no problem which can be seen on the front end dynamically, however, I am unable to send image to the mongo database which i've been trying to achieve now for quite some time.
I am using multer and axios to try and sent the file over as the application is a react app. I think the problem is to do with the "req.file" within the back end of the application. The code below is my endpoint:
api.js
var express = require('express');
var bodyParser = require('body-parser');
var cors = require('cors')
var app = express();
var mongodb = require('mongodb');
var path = require('path');
var fsextra = require('fs-extra');
var fs = require('fs')
var util = require('util')
var multer = require('multer')
var upload = multer( {dest: __dirname + '/uploads'} )
var ejs = require('ejs')
const MongoClient = require('mongodb').MongoClient;
app.use(express.static(path.resolve(__dirname, '../react', 'build')));
app.get('*',(req,res)=>{
res.sendFile(path.resolve(__dirname, '../react', 'build', 'index.html'));
});
console.log(__dirname)
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', __dirname);
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
var db;
mongodb.MongoClient.connect('mongodb://<mydbdetails>', (err, database) => {
if (err) {
console.log(err)
process.exit(1);
}
db = database;
console.log('Database connection is ready')
});
var server= app.listen(process.env.PORT || 8082, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
app.post('/api/submitImage', upload.single('inputForm'), function(req,res){
var file = req.body.file
if (file == null) {
// If Submit was accidentally clicked with no file selected...
//res.render('admin', { title:'Please select a picture file to submit!'});
res.send({success: false, message: "dsfdsg"})
console.log('There is no file present')
console.log(req.file,'file')
}
else{
// read the img file from tmp in-memory location
var newImg = fs.readFileSync(req.files.path);
console.log(newImg,'details of the new image')
// encode the file as a base64 string.
var encImg = newImg.toString('base64');
console.log(encImg,'kdfjndodj')
// define your new document
var newItem = {
description: req.body.description,
contentType: req.file.mimetype,
size: req.files.size,
img: Buffer(encImg, 'base64')
};
db.collection('products').insert(newItem, function(err, result){
if(err) {
console.log(err)
}
var newoid = new ObjectId(result.ops[0]._id);
fs.remove(req.file.path, function(err) {
if (err) { console.log(err) };
res.render('./src/components/adminContainer.js', {title:'Thanks for the Picture!'});
});
})
}
})
The next code is the how I am trying to send it over using Axios:
import axios from 'axios';
class ProductsApi {
static submitProduct(name,prices,callback){
axios.post('http://localhost:8082/api/submitProduct', {name: name, prices: prices})
.then( response => {
callback(response)
})
}
static viewName(callback){
axios.post('http://localhost:8082/api/retrieveName')
.then( response => {
return callback(response)
})
}
static viewPrice(callback){
axios.post('http://localhost:8082/api/retrievePrice')
.then( response => {
return callback(response)
})
}
static viewProducts(callback){
axios.post('http://localhost:8082/api/retrieveProducts')
.then( response => {
return callback(response)
})
}
static submitImages(image,callback){
axios.post('http://localhost:8082/api/submitImage',{image: image})
.then( response => {
return callback(response)
console.log('response has been made,', image,'has been recieved by axios')
})
}
}
export default ProductsApi;
The last file is how I am trying to send the file to the database using react with event handlers:
import React, { Component } from 'react'
import '../App.css'
import AppHeader from './appHeader.js'
import ProductsApi from '../api/axios.js'
const AdminContainer = () => {
return(
<div>
<AppHeader />
<FormContainer />
</div>
)
}
class FormContainer extends Component{
constructor(props){
super(props);
this.state={
file: '',
inputName: '',
inputPrice: '',
image: ''
};
this.handleNameChange = this.handleNameChange.bind(this);
this.handlePriceChange = this.handlePriceChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.sendName = this.handleSubmit.bind(this);
}
handleNameChange(e){
console.log(e.target.value)
this.setState({
name : e.target.value,
})
}
handlePriceChange(e){
console.log(e.target.value)
this.setState({
prices : e.target.value
})
}
sendName(e){
this.setState({
inputName: e.target.value,
inputName:e.target.value
})
}
handleSubmit(e){
e.preventDefault();
console.log('attempting to access axios...')
ProductsApi.submitProduct(this.state.name, this.state.prices, resp => {
console.log('response has been made', resp)
//if error message, add to state and show error message on front end
this.setState({
inputName:this.state.name,
inputPrice:this.state.prices
},function(){
console.log(resp,'this is resp')
console.log('Axios has send ',this.state.name,' to the database')
});
})
console.log(this.state.prices,'This is the new price')
console.log(this.state.name,'This is the new name')
ProductsApi.submitImages(this.state.image, response => {
console.log('axios has been notified to submit an image...')
this.setState({
image: this.state.image
},function(){
console.log('Image submission axios response details are as follows: ', response)
console.log(this.state.image, ': has been sent to the db')
})
})
}
render(){
return(
<div>
<h2>Add a new product to the Shop</h2>
<div className='formWrapper'>
<div className='center'>
<form name='inputForm' encType='multipart/form-data' method='post'>
<label>
Name:
<input value = {this.state.name} onChange={this.handleNameChange} type="text" placeholder='Name' /><br />
Price:
<input value = {this.state.prices} onChange={this.handlePriceChange} type='text' /><br />
</label>
<label>
Choose an Image:
<input className='imgInsert' name ='inputForm' type='file'/>
</label>
<div>
<img className = 'previewImage' value={this.state.image}/>
</div>
<button className='btn updateBtn' onClick={(e) => this.handleSubmit(e)}>Submit</button>
</form>
</div>
</div>
</div>
)
}
}
export default AdminContainer
Common errors I am getting when trying debug it is
TypeError: Cannot read property 'path' of undefined."
and "file" being undefined.

When using multer to save images you need to make sure that the image comes to the server as form data. this is because multer requires the multipart/form-data encoding which you do not get when submitting a form with an ajax request unless if you specifically do something to make it happen.
You can do this by using the FormData object. Here is an example of this being used. I hope this helps.

Related

Trying to post data via html-form and JavaScript to RESTapi – gets 404 Cannot Post?

I have googled a lot, gone through a lot of questions but can't find an answer.
I have built a simple RESTapi with node and mongoDB, using express and mongoose. The database is hosted on Atlas. The RESTapi works fine when accessing with postman, no problem there.
To access and use the RESTapi via the site I get the GET and DELETE method to work, but when trying to post data with a form I get the error “Cannot Post/ 404”. I have tried a lot of things but can´t get it to work. (I don't know it it is related, but the content-security policies which makes some scripts don't load, I have tried to allow everything in the head meta-info in index.html, but it doesn't make a change)
Request headers
Accept
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding
gzip, deflate
Accept-Language
en-US,en;q=0.5
Cache-Control
no-cache
Connection
keep-alive
Content-Length
530
Content-Type
multipart/form-data; boundary=---------------------------52045656921129358052645853016
Host
localhost:3000
Origin
http://localhost:3000
Pragma
no-cache
Referer
http://localhost:3000/
Upgrade-Insecure-Requests
1
The RESTapi and the site accessing is in the same folder, here is the project structure:
Here is the code:
js/main.js
window.onload = loadCourses();
// Variebles from the form
let formCreate = document.getElementById("formCreate");
let courseIdIn = document.getElementById("courseId");
let courseNameIn = document.getElementById("courseName");
let coursePeriodIn = document.getElementById("coursePeriod");
let message_form = document.getElementById("message_form");
const myForm = document.getElementById('formCreate');
myForm.addEventListener('submit', (e) => {
console.log('Hello from eventlistner');
e.preventDefault();
addCourse();
})
// GET courses
function loadCourses() {
$.getJSON("http://localhost:3000/courses", function(data) {
//rensa listan
console.log(data);
$("#tbody").html("");
for(let i = 0; i<data.length; i++) {
$("tbody").append("<tr><td>" + data[i]._id + "</td>" + "<td>"+ data[i].courseId + "</td>" + "<td>" + data[i].courseName +
"</td>" + "<td>" + data[i].coursePeriod + "</td>" + "<td><img class='deleteSize' onclick='deleteCourse(\""+data[i]._id+"\")' src='images/delete-photo.svg'alt='ikon radare'></td></tr>");
}
});
}
// DELETE course
function deleteCourse(id) {
console.log(id)
$.ajax({
type: "DELETE",
url: "http://localhost:3000/courses/" + id
}).done(function(response) {
console.log(response);
//ladda om listan
loadCourses();
});
}
// add course
function addCourse() {
console.log("Hi from add Course");
let courseIdEl = courseIdIn .value;
let courseNameEl = courseNameIn.value;
let coursePeriodEl = coursePeriodIn.value;
let courseObj =
{
"courseId": courseIdEl.value,
"courseName": courseNameEl.value,
"coursePeriod": coursePeriodEl.value
}
console.log(courseObj);
//Skapar fetch-anrop
fetch('http://localhost:3000/courses', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': '*/*',
},
body: JSON.stringify(courseObj)
})
.then(response => response.json())
.then(data => {
// message
let message = data.message;
message_form.innerHTML = message;
//document.getElementById("message_form").innerHTML = message;
loadCourses();
formCreate.reset();
})
.catch(error => {
console.log('Error: ', error);
})
}
the index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-policy" content="default-src *;
script-src *;
connect-src *;">
<link rel="stylesheet" href="css/style.css">
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="js/main.js"></script>
<script src="main2.js"></script>
<title>Moment 3 - mongoose.js</title>
</head>
<body>
<h1>Moment 3 - mongoose.js</h1>
<table>
<thead>
<tr>
<th>ID</th>
<th>Kurs</th>
<th>Kursnamn</th>
<th>Period</th>
<th>Radera</th>
</tr>
</thead>
<tbody id="tbody">
<tr>
<td>1</td>
<td>DT162G</td>
<td>JavaScript-basar webbutveckling</td>
<td>1</td>
<td><img class="deleteSize" onclick="deleteCourse()" src="images/delete-photo.svg" alt="ikon radare">
</td>
</tr>
</tbody>
</table>
<h3>Create course:</h3>
<form class="forms" action="" id="formCreate" method="POST" enctype="multipart/form-data">
<!--fält för formulär, hela den grå delen-->
<fieldset id="field">
<p class="pfield" id="message_form"></p>
<label for="courseId">Kurskod:</label><br>
<input type="text" name="courseId" id="courseId" class="input">
<br>
<label for="courseName">Kursnamn:</label><br>
<input type="text" name="courseName" id="courseName" class="input">
<br>
<label for="coursePeriod">Kursperiod:</label><br>
<input type="number" id="coursePeriod" name="coursePeriod" min="1" max="2">
<div class="btn-wrapper">
<button type="submit" name="submitPost" id="btn-create" class="btn btn2">Publish</button>
<button type="reset" name="deletePost" id="btn-reset" class="btn btn2 btn-reset">Delete
field</button>
</div>
</fieldset>
</form>
</body>
</html>
RESTapi code
routes/courses.js
const express = require('express');
const router = express.Router();
// Hämtar schemamodel
const Courses = require('../models/CourseModel');
// Get all courses
router.get('/', async (req, res) => {
try {
const allCourses = await Courses.find();
if(!allCourses) {
throw Error('No items found');
} else {
res.status(200).json(allCourses);
}
} catch(err) {
res.status(500).json( {msg: err})
}
})
// GET one course
router.get('/:id', getCourse, (req, res) => {
res.json(res.course)
})
// Create course
router.post('/', async (req, res) => {
const newCourse = new Courses({
courseName: req.body.courseName,
courseId: req.body.courseId,
coursePeriod: req.body.coursePeriod
});
try {
const course = await newCourse.save();
if(!course) {
throw Error('Something went wrong while saving the post =( ');
} else {
// It worked ok, post is created
res.status(201).json(course);
}
} catch (err) {
// bad input from user = 400
res.status(400).json( {msg: err})
}
});
// UPDATE one course
router.patch('/:id', getCourse, async (req, res) => {
// options new = true makes mangoose send back updated data and not old
let options = { new: true };
try {
const course = await Courses.findByIdAndUpdate(req.params.id, req.body, options);
if(!course) {
throw Error ('Something went wrong while updating the post =( ');
} else {
// It worked ok, post is created
res.json(course).status(201).json( {success: true});
}
} catch {
res.status(400).json( {message: err.message})
}
})
// DELETE one course
router.delete('/:id', getCourse, async (req, res) => {
try {
await res.course.deleteOne();
res.status(200).json( {message: 'Success: Course is deleted!'})
} catch (err){
res.status(503).json( {message: err.message})
}
})
// Creating middlewhere function to re-use, findbyid. Middlewhere idé = webdev simplified
async function getCourse(req, res, next) {
let course;
try {
course = await Courses.findById(req.params.id)
if (course == null) {
return res.status(404).json( {message: 'Cant find any course with that ID'})
}
} catch (err) {
return res.status(500).json( {message: err.message})
}
res.course = course;
next();
}
module.exports = router;
models/CourseModel.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CourseSchema = new Schema( {
courseName: {
type: String,
required: true
},
courseId: {
type: String,
required: true
},
coursePeriod: {
type: Number,
required: true
}
});
module.exports = mongoose.model('Courses', CourseSchema );
server.js
require('dotenv').config();
const express = require('express');
const app = express();
const path = require("path");
const mongoose = require('mongoose');
//const { MONGO_URI } = require('./config');
// Connect to MongoDB
mongoose.connect(process.env.MONGO_URI,{ useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false })
.then(() => console.log('Connected to Mongo Database.'))
.catch(err => console.log(err));
//BodyParser Middleware, for use of JSON in body
app.use(express.json());
// skapa statisk sökväg
app.use(express.static(path.join(__dirname, 'public')));
// Routes
const courseRoutes = require('./routes/courses.js')
app.use('/courses', courseRoutes)
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log (`Server run at port ${PORT}`));
well, it was a stupid mistake in HTML, the script source tag for the javascript-file main.js was in the head section. Of course, it must be in the bottom just before the body-tag. So stupid of me.

nextjs errors with form handling

I'm learning react and nextjs, the page works perfectly without the integration of a UI library, since i installed react suite my page with the login form doesn't work anymore, it returns me an error: TypeError: Cannot read property 'value 'of undefined
My code is:
import React, { useState } from "react"
import { setCookie, parseCookies } from "nookies"
import { useRouter } from "next/router"
import { Form, FormGroup, FormControl, ControlLabel, HelpBlock, Button, Input } from 'rsuite';
const Login = () => {
// set initial const
const router = useRouter()
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
// handle event submit
const handleSubmit = async (e) => {
e.preventDefault();
// fetch user
const response = await fetch( process.env.urlHeadless + '/api/cockpit/authUser', {
method: "post",
headers: {
"Content-Type": "application/json",
'Cockpit-Token': process.env.loginKey,
},
body: JSON.stringify({
user: username,
password: password
})
})
// if user exists
if (response.ok) {
const loggedUser = await response.json()
// set cookie with api_key
setCookie("", "tokenId", loggedUser._id, {
maxAge: 30 * 24 * 60 * 60,
path: "/"
})
// redirect to dashboard
return (router.push("/dashboard"))
} else if (response.status === 412) {
alert('compila il form')
} else if (response.status === 401) {
alert('credenziali di accesso errate')
}
}
return (
<>
<Form>
<FormGroup>
<ControlLabel>Username</ControlLabel>
<FormControl type="text" value={username} onChange={(e) => setUsername(e.target.value)} />
<HelpBlock>Required</HelpBlock>
</FormGroup>
<FormGroup>
<ControlLabel>Password</ControlLabel>
<FormControl type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
</FormGroup>
<FormGroup>
<Button appearance="primary" onClick={handleSubmit}>Submit</Button>
</FormGroup>
</Form>
</>
)
}
// async function
export async function getServerSideProps(context) {
// get cookie value
const cookies = parseCookies(context).token;
// if cookie has value
if (cookies) {
return {
// redirect to dashboard
redirect: {
destination: '/dashboard',
permanent: false,
},
}
}
return { props: {} };
}
export default Login;
I also tried using useRef instead of useState, but it didn't work ... where am I wrong? thank you in advance
Looks like rsuite components might have a different onChange implementation, as described in their docs
onChange (formValue:Object, event:Object) => void Callback fired when data changing
If you want the event, try changing the onChange callback in your code to take the second parameter:
<FormControl
...
onChange={(value, e) => setUsername(e.target.value)}
/>

I get "ForbiddenError: invalid csrf token" when I try to use {cookie: { secure: true }} session configuration. How do I implement this?

I do not understand why this is not working. I get this "ForbiddenError: invalid csrf token" message rendered when i click login, but I read that the {cookie: {httpOnly: true, secure: true}} options must be enabled in the session in order to get a relatively secure app running (I use JWT and am a newbie in sessions and cookies)
Here are my files:
app.js
// ____ Imports ____
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const sessionConfig = require('./middleware/sessions');
const userProvider = require('./middleware/userProvider');
const connectDB = require('./services/db');
const csrf = require('csurf');
// ____ Middlewares ____
const app = express();
const csrfProtection = csrf();
app.set('view engine', 'ejs');
app.set('views', 'views');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(sessionConfig);
app.use(userProvider);
app.use(csrfProtection);
app.use((req, res, next) => {
res.locals.isAuth = req.session.isAuth;
res.locals.csrfToken = req.csrfToken();
next();
});
// ____ Routes ____
const adminRoutes = require('./routes/admin');
const shopRoutes = require('./routes/shop');
const authRoutes = require('./routes/auth');
const errorController = require('./controllers/error');
app.use('/admin', adminRoutes);
app.use(shopRoutes);
app.use(authRoutes);
app.use(errorController.get404);
// ____ Database & Server spin-up ____
const PORT = process.env.PORT || 3000; //deployment looks for process.env.PORT
connectDB(() => {
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
});
./middleware/sessions.js
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const config = require('config');
const store = new MongoDBStore({
uri: config.get('mongoURI'),
collection: 'sessions',
});
const sessionConfig = session({
secret: config.get('sessionSecret'),
resave: false,
saveUninitialized: false,
store: store,
cookie: { httpOnly: true, secure: true },
});
module.exports = sessionConfig;
./middleware/isAuth.js
module.exports = (req, res, next) => {
if (!req.session.isAuth) {
return res.redirect('/login');
}
next();
};
./middleware/userProvider.js
const User = require('../models/user');
module.exports = async (req, res, next) => {
try {
if (!req.session.user) {
return next();
}
let user = await User.findById(req.session.user._id);
req.user = user;
next();
} catch (error) {
console.log(error);
}
};
postLogin controller (passes through isAuth middleware)
exports.postLogin = async (req, res) => {
try {
let { email, password } = req.body;
let user = await User.findOne({ email: email });
let doMatch = await bcrypt.compare(password, user.password);
if (doMatch) {
console.log('Match!');
//use .save() method to make sure it redirects only when session is already created
req.session.user = user;
req.session.isAuth = true;
return req.session.save(() => {
res.redirect('/');
});
} else {
return res.redirect('/login');
}
} catch (error) {
console.log(error);
}
};
./views/auth/login.ejs
<%- include('../includes/head.ejs') %>
<link rel="stylesheet" href="/css/forms.css">
<link rel="stylesheet" href="/css/auth.css">
</head>
<body>
<%- include('../includes/navigation.ejs') %>
<main>
<form class="login-form" action="/login" method="POST">
<div class="form-control">
<label for="email">E-Mail</label>
<input type="email" name="email" id="email">
</div>
<div class="form-control">
<label for="password">Password</label>
<input type="password" name="password" id="password">
</div>
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<button class="btn" type="submit">Login</button>
</form>
</main>
<%- include('../includes/end.ejs') %>
A session does get created in mongoDB, but no user or isAuth (shown in the document below as isLoggedin) is defined.
After narrowing down to the secure: true problem (when I first asked I didn't know what was causing this behavior), I found this thread explaining that http servers do not get secure: true cookies (express-session secure: true)
In localhost I use http so of course this doesn't work. When I put this on a production environment it worked :)

Uploading multiple files through form from different fields and storing into mongodb databse using express multer

I am trying to upload two image files a database called cast using multer .I am taking the images as input from a form. I realized that some times it takes files from all the input fields but sometimes it accepts only one image file as input.
Can anybody please help me?Thank you in advance
adminUpload.ejs
<html>
<body>
<form class="uploadForm" method="post" action="/admin/postFile" enctype="multipart/form-data">
<label>Enter the name of the actor</label><br>
<input type="text" name="actor"><br>
<label class="control-label">Upload the image of the actor</label><br>
<input name="uplactor" type="file" class="file"><br>
<label>Enter the name of the actress</label><br>
<input type="text" name="actress"><br>
<label class="control-label">Upload the image of the actress</label><br>
<input name="uplactress" type="file" class="file"><br>
<input type="submit" value="submit" />
</form>
</body>
</html>
AdminRouter.js
const express = require('express')
const router = express.Router()
const controller=require('../Controller/Admin');
const multerFileUpload=require("../Models/Admin")
router.get('/postFile',(req,res)=>{
res.render('adminUpload.ejs');
})
var tempupload=multerFileUpload.upload.fields([
{name: 'uplactor',maxCount: 1},
{name: 'uplactress',maxCount: 1}])
router.post("/postFile",tempupload,controller.uploadDB)
module.exports=router;
Admin.js
const multer = require('multer');
const storage= multer.diskStorage({
destination: (req, file, cb) => {
if (file.fieldname === 'uplactor'||file.fieldname === 'uplactress'||file.fieldname === 'director'||file.fieldname === 'uplSideCharacter') {
// if uploading cast photo
cb(null, 'public/cast_images')
}
else if(file.fieldname === 'uplTrailer'){
// else uploading trailer
cb(null, 'public/trailers')
}
else if(file.fieldname === 'uplMovie'){
// else uploading movie
cb(null, 'public/movies')
}
else if(file.fieldname === 'uplposter'){
// else uploading poster
cb(null, 'public/posters')
}
cb(null, 'public/posters');
},
filename: (req, file, cb) => {
cb(null, file.originalname)
}
});
const fileFilter = (req, file, cb) => {
if(file.fieldname === 'uplactor'||file.fieldname === 'uplactress'||file.fieldname === 'director'||file.fieldname === 'uplSideCharacter'||file.fieldname === 'uplposter'){
if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
return cb(new Error('You can upload only image files!'));
}
else{
cb(null, true);
}
}
if(file.fieldname === 'uplMovie'||file.fieldname === 'uplTrailer'){
if (!file.originalname.match(/\.(mp4|mp3)$/)) {
return cb(new Error('You can upload only video files!'));
}
else{
cb(null, true);
}
}
};
exports.upload = multer({ storage:storage, fileFilter: fileFilter });
Admin.js(Controller file)
const Cast = require('../Models/Cast');
exports.uploadDB=async (req,res)=>{
try{
console.log(req.files)
console.log(req.files.uplactor[0])
console.log(req.files.uplactress[0])
const actor=new Cast({
name:req.body.actor,
image:req.files.uplactor[0].filename
})
const actress=new Cast({
name:req.body.actress,
image:req.files.uplactress[0].filename
})
await actor.save();
await actress.save();
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.send("hello");
}catch(err){
res.send(err);
}
}
app.js
'use strict';
const express = require('express');
const http = require('http');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const AdminRouter = require('./Routes/AdminRoutes');
const mongoose = require('mongoose');
const app=express()
const server = http.createServer(app);
server.listen(3000, 'localhost', () => {
console.log('server running');
});
app.use(morgan('dev'));
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.set('views', 'views');
app.set('view engine', 'ejs');
app.use('/admin',AdminRouter);
//connection to mongodb
const url = 'mongodb://localhost:27017/Movie';
const connect = mongoose.connect(url, {useNewUrlParser : true, useUnifiedTopology: true } );
connect.then(() => {
console.log("Connected correctly to server");
}, (err) => { console.log(err); });
Cast.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CastSchema = new Schema({
name: {
type: String,
required: true,
unique: true
},
image: {
type: String,
required: true
}
})
const Cast = mongoose.model('Cast', CastSchema)
module.exports= Cast
I have taken your code and debug it.At my end i have used 4 images(2 of them having size in KB and 2 are 9-10 MB) for testing purpose and found that problem exist when either one or both input file of large size(MBs).
so,in uploadDB method you've created two instance of Cast model and then save it.to solve your problem create one instance save it and then create second instance and save it.
const actor = new Cast({
name: req.body.actor,
image: req.files.uplactor[0].filename
});
await actor.save();
console.log(req.files.uplactress[0]);
const actress = new Cast({
name: req.body.actress,
image: req.files.uplactress[0].filename
});
await actress.save();
hope this might help
Output:

MERN stack binary image is just a black square

I'm building a full-stack app with a MERN stack (mongo db, Express, React and Node.js)
I'm currently able to cave my image to the mongo db as a binary file.
The the mongo shell database output is
"img" : BinData(0,"QzpcZmFrZXBhdGhcc2FtcGxlLnBuZw=="),
so I would assume that the upload is fine.
When it comes to converting it back to an image on the front end I am using
src={`data:image/png;`+btoa(`${Buffer.from(img.data).toString('base64')}`)}
which gives me a string that looks like this...
data:image/png;UXpwY1ptRnJaWEJoZEdoY2MyRnRjR3hsTG5CdVp3PT0=
However, on the front-end it shows a broken image icon and when I go to this link it just shows
a teeny tiny black square.
I have tried a lot of combinations of concatenating the string but can't seem to get it to display.
Thanks in advance !
Ok, so after many differnet strategies I managed to combine a few bit of code here and there plus some improvisation to build this...
ImageUpload.js
import React from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
class ImageUpload extends React.Component {
constructor(props) {
super(props);
this.state = {
image: {
name: "",
img: ""
},
submitted: false
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const { name, value } = event.target;
const { image } = this.state;
this.setState({
image: {
...image,
[name]: value,
}
});
}
onSelectChange = (e) => {
const values = [...e.target.selectedOptions].map(opt => opt.value);
this.props.onChange(values);
};
handleSubmit(event) {
event.preventDefault();
console.log(this.state);
this.setState({ submitted: true });
const { image } = this.state;
if (image.name) {
this.props.register(image);
}
}
_onChange = (e) => {
const file = this.refs.uploadImg.files[0]
const reader = new FileReader();
reader.onloadend = () => {
this.setState({
image: {
img: reader.result
}
})
}
if (file) {
reader.readAsDataURL(file);
this.setState({
image: {
img: reader.result
}
})
}
else {
this.setState({
image: {
img: ""
}
})
}
}
render() {
const { registering } = this.props;
const { image, submitted } = this.state;
console.log(this.handleChange);
render() {
const { registering } = this.props;
const { image, submitted } = this.state;
console.log(this.handleChange);
return (
<div className="col-md-9 col-md-offset-3">
<form name="form" onSubmit={this.handleSubmit}>
<div className={'form-group' + (submitted && !image.img ? ' has-error' : '')}>
<label htmlFor="img">Image</label>
<input
ref="uploadImg"
type="file"
name="selectedFile"
onChange={this._onChange}>
{/* value={toString(window.form.elements[0].nextElementSibling.src)}> */}
</input>
<img src={this.state.image.img} />
{submitted && !image.img &&
<div className="help-block">Image is required</div>
}
</div>
<div className="form-group">
<button className="btn btn-primary">Register Building</button>
{registering && }
<Link to="/home" className="btn btn-link">Cancel</Link>
</div>
</form>
</div>
The mongoose Schema is just a simple string:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
Apartment = require('../apartments/apartment.model')
const schema = new Schema(
name: { type: String },
img: { type: String }
}
);
schema.set('toJSON', { virtuals: true });
module.exports = mongoose.model('image', schema);
Hope it helps anyone else. Also if anyone wouldn't mind explaining the potential flaws in uploading extrememly looong strings for images (and any solutions to this) that'd be a big help too. Would there be a way to enter this as a Buffer base64 and convert it? would the db read it this way ?
Thanks !