My MERN/Redux app enables image uploads which saves Mongo Atlas documents AND saves each file in a static directoy.
Note: This is for a client who is an artist. He draws commissions for people, so I named the Model Commission
CODE:
~server.js:
-----
app.use('/uploads', express.static('uploads');
-----
~multer upload code
-----
const multer = require('multer');
const storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, './uploads/');
},
filename: function(req, file, cb) {
cb(null, Date.now() + file.originalname);
}
});
const fileFilter = (req, file, cb) => {
if(file.mimetype === 'image/jpeg' || file.mimetype === 'image/jpg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(null, false);
};
};
const upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 5
},
fileFilter: fileFilter
});
// ALSO TRIED
const upload = multer({
storage: multerS3({
s3: s3,
bucket: process.env.S3_BUCKET,
key: function (req, file, cb) {
console.log(file);
cb(null, Date.now() + file.originalname);
}
}),
limits: {
fileSize: 1024 * 1024 * 5
},
fileFilter: fileFilter
});
-----
~commissions.js (route file)
-----
// AWS CODE
const ID = process.env.AWS_ACCESS_KEY_ID;
const SECRET = process.env.AWS_SECRET_ACCESS_KEY;
const BUCKET_NAME = process.env.S3_BUCKET;
const s3 = new AWS.S3({
accessKeyId: ID,
secretAccessKey: SECRET
});
const uploadFile = (imagename, imagedata) => {
const fileContent = fs.readFileSync(imagedata);
const params = {
Bucket: BUCKET_NAME,
Key: imagename,
Body: fileContent
};
s3.upload(params, function(err, data) {
if(err) {
throw err;
}
console.log(`File uploaded to S3 successfully: ${data.Location}`)
});
};
// @route POST /commissions
// @descrip Create a new commission
// @access Private
router.route('/').post(upload.single('imageData'), authorize, (req, res) => { <<~~ multer upload()
uploadFile(req.body.imageName, req.file.path); <<~~ sends img to S3 bucket
const newCommission = new Commission({
imageName: req.body.imageName,
imageData: req.file.path,
title: req.body.title,
description: req.body.description,
price: req.body.price
});
newCommission.save() <<~~saves doc to mongo atlas
.then(commission => res.json(commission))
.catch(err => res.status(400).json(`Create new commission failed: ${err}`));
});
-----
In my view, the problem is one of two things (or both):
app.use('/uploads', express.static('uploads'))
and
const storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, './uploads/'); <<~~the actual image storage
},
filename: function(req, file, cb) {
cb(null, Date.now() + file.originalname);
}
});
When I upload a document to Mongo, it's imageData
property is uploadsimage_name.jpg
And in the Front End, I merely display it via commission.imageData
So I figure I need to have the image pointed to the S3 bucket. But I can't figure out how.
When my multer storage
is multer.diskStorage()
, the imageName
is stored in S3 bucket. So even if I were retrieving it properly, what I need is imageData
.
When I used the upload
code that uses multer-s3
, the file that ends up in my S3 bucket is the actual imageData
along with the proper MIMEtype, but this breaks my Mongo request and gives the following error:
TypeError: Cannot read property 'path' of undefined
..which is pointing to uploadFile(req.body.imageName, req.file.path);
...which doesn't make sense because that's what sends the file to S3! And that's the part that actually works