0

I can upload images to my s3 bucket, but have been unable to pass the corresponding file url to my MongoDB database. The best I have been able to do is update my image field with a predefined string name. Specifically, I want to change 'TestURL.png' to match the name of the file being saved in my route 'Date.now().toString() + '-' + file.originalname)' but have been unable to do so.

Note, when I try to access 'req.file' the object comes back empty. Also, if my code looks different than other multer-s3 tutorials its because I haven't been able to find any to work, besides what is being used below.

uploadController.js

import asyncHandler from 'express-async-handler';
import Recipe from '../models/recipeModel.js';

// @description Upload
// @route PUT /api/uploadAWS/:id
// @access Private
const uploadRecipeCoverImage = asyncHandler(async (req, res) => {
  const {
    recipe_cover_image,
  } = req.body

  const uid = req.params.id
  const recipe = await Recipe.findById(uid)

  const uploadImage = { recipe_cover_image: 'TestURL.png' }

  Recipe.findByIdAndUpdate(uid, uploadImage, { new: true })
    .then((recipe) => res.status(200).json({success:true, recipe:recipe}))
    .catch((recipe) => res.status(400).json({success:false, error:err}))

export {
  uploadRecipeCoverImage
} 

uploadAWSRoutes.js

import express from 'express';
import aws from 'aws-sdk';
import multer from 'multer';
import multerS3 from 'multer-s3';
import path from 'path';
import {
  uploadRecipeCoverImage,
} from '../controllers/uploadController.js';
import { protect, admin } from '../middleware/authMiddleware.js';

const router = express.Router();

aws.config.update({
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  region: 'us-west-2',
  signatureVersion: 'v4'
})

const s3 = new aws.S3()

function checkFileType(file, cb) {
  const filetypes = /jpg|jpeg|png/
  const extname = filetypes.test(path.extname(file.originalname).toLowerCase())
  const mimetype = filetypes.test(file.mimetype)

  if(extname && mimetype) {
    return cb(null, true)
  } else {
    cb('Images only!')
  }
}

const upload = multer({
  limits: { fileSize: 2000000 },
  fileFilter: function(req, file, cb) {
    checkFileType(file, cb)
  },
  storage: multerS3({
    s3: s3,
    bucket: 'recipebook-recipe-cover-images',
    acl: "public-read",
    metadata: function (req, file, cb) {
      cb(null, { fieldName: file.fieldname });
    },
    key: function (req, file, cb) {
      cb(null, Date.now().toString() + '-' + file.originalname);
    },
  }),
})

const singleUpload = upload.any()

router.route('/:id')
  .put(singleUpload, protect, uploadRecipeCoverImage)

recipeModel.js (if not clear from above)

import mongoose from 'mongoose';

const recipeSchema = mongoose.Schema(
  {
    ...
    recipe_cover_image: {
      type: String,
      required: true
    },
    ,,,
)

const Recipe = mongoose.model('Recipe', recipeSchema);

export default Recipe;
jasontulloch
  • 31
  • 1
  • 6
  • everything looks good, you can access file object in `req.files` for `any()`, and access full s3 url in location `req.files[0].location` – turivishal Feb 04 '21 at 13:53
  • @turivishal I can't thank you enough! It worked like a charm and was the simple solution I was looking for! – jasontulloch Feb 04 '21 at 14:30
  • welcome, I am voting to close this question, similar issue is here [How to get direct URL to multipart file uploaded via Node.js](https://stackoverflow.com/questions/59054367/how-to-get-direct-url-to-multipart-file-uploaded-via-node-js) – turivishal Feb 04 '21 at 14:35
  • Well there it is... My only hesitation is that I had spent hours looking on SO for this solution and couldn't find the related post. Maybe its just how I searched, but I haven't seen anyone actually implement my approach of using .any() and would think this post can help someone in the future. As a novice in Node, that description on the link provided only makes sense now that it has been clearly described. – jasontulloch Feb 04 '21 at 14:41

0 Answers0