0
votes

I read all the questions related to this already and nothing works. I spent the entire day on this and I can't figure out what's wrong.

I am trying to upload a file to my database using React, mongoose, mongoDB and express/node.

Here is what I already did:

  • Added method="post" and enctype="multipart/form-data" to my form
  • the "name" property of the file input is "icon" and in the middleware upload.single("icon") too.

On submit I have a function action that is called.

export const updateUserIconette = icon => async dispatch => {
    console.log("Number 1");
    console.log(icon);
    try {
        const res = await axios.post("/me", icon);
        dispatch({
            type: UPDATE_PROFILE_SUCCESS,
            payload: res.data
        });
    } catch (err) {
        const errors = err.response.data.errors;
        if (errors) {
            errors.forEach(error => dispatch(setAlert(error.msg, "danger")));
        }
        dispatch({
            type: UPDATE_PROFILE_ERROR
        });
    }
};

Here, the console.log number 1 logs and the log of icon too, which is a file object.

And the API Post route is here:

const multer = require("multer");
const storage = multer.diskStorage({
    destination: function(req, file, callback) {
        callback(null, "./uploads/");
    },
    filename: function(req, file, callback) {
        callback(null, file.originalname);
    }
});
const fileFilter = (req, file, callback) => {
    if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
        callback(null, true);
    } else {
        callback(null, false);
    }
};
const upload = multer({ storage: storage, fileFilter: fileFilter });

router.post(
    "/",
    [
        auth,
        upload.single("icon")
    ],
    async (req, res) => {

console.log("number 2")
console.log(req.file)
        // Build the Profile object
        const profileFields = {};
        profileFields.user = req.user.id;
        if (req.body.username) profileFields.username = req.body.username;
        if (req.body.bio) profileFields.bio = req.body.bio;
        if (req.body.location) profileFields.location = req.body.location;
        if (req.file) profileFields.icon = req.file.path;

        try {
            let user = await User.findOne({ _id: req.user.id });

            if (user) {
                //Update
                user = await User.findOneAndUpdate(
                    { _id: req.user.id },
                    { $set: profileFields },
                    { new: true }
                );
                return res.json(user);
            }
            await user.save();
            res.json(user);
        } catch (err) {
            console.error(err.message);
            res.status(500).send("Server Error");
        }
    }
);

Here, the console.log number 2 logs but not the req.file because it is empty.

1
Do you have a github repo? It'd be easier to debug.Matt Carlotta
Our repo is private but I just updated the question with a more accurate code, thanks a lot for your reply :)Jasmine
There are many moving parts when it comes to uploading files, so without a reproducible example, it's going to be a guessing game. If you can, create a stripped down version of what you have (again, stripped down, doesn't need styles or anything fancy -- just needs to contain your client and server logic in regards to this icon uploading). If not, I can create a small working repo, but it may not match your logic and may not be of much help to you.Matt Carlotta
i will add you to the repos if that is OK with youJasmine
Hmm, let's try this: I'll create a small stripped down working repo. Nothing fancy. Then you can use it as a reference point against your project. I'll use everything you've listed in the question tags. If, after looking at my code, it doesn't help, then you can add me to your repos.Matt Carlotta

1 Answers

0
votes

Alright, here's a working demo using react, multer, express, mongodb and mongoose. It's not fancy, pretty much bare bones, but it works. What you should do is step through your project and make sure each file/function/middleware works as intended in the flow (see flow example below).

Github repo: https://github.com/mattcarlotta/upload-image-example


Follow the README for instructions on how to run it.

All important files will have notes as to what their function does.

Files to focus on:

Flow:

  • User adds a file (image) and an email address and clicks Submit to send a POST request to the API.
  • The POST request first passes through the multer middleware.
  • If valid, then the request is handled via the upload icon route.
  • The route passes it to the saveIcon middleware.
  • The saveIcon middleware saves the image to uploads then passes the request to the createIcon controller.
  • The controller saves the email and icon filepath to the mongodb database, and then sends back a response (message and remoteicon) to the client-side form.
  • The client-side form receives a res (response) from the API and sets it to state.
  • When the state is updated, the remoteicon is set as a src to an img element, which in turn, makes a GET request back to the API, which in turns sends back the uploaded image.

Ideally, most of this flow will be a microservice (and not attached to your main application), as it will vastly simplify your structure. More info can be found here.