Search code examples
reactjsmongodbexpressmernmulter-gridfs-storage

How do I solve gridFS TypeError: Cannot read properties of undefined (reading '_id') [0] at GridFSBucketWriteStream.emitFile


I am trying to upload image to mongoDD from a react application and I have always gotten above error message which is crashing my application.

My Client code:

    // to be triggered by onChange attribute of a file input

    const uploadFileHandler = async (e) => {
    const file = e.target.files[0];
    const formData = new FormData();
    formData.append("image", file);

    try {
      const config = {
        headers: {
          "Content-Type": "multipart/form-data",
          Authorization: `Bearer ${userInfo.token}`,
        },
      };
      if (file) {
        setErrorMessage(""); // Clear any previous error message.
        dispatch({ type: UPLOAD_CATEGORY_IMAGE_REQUEST });
        const { data } = await axios.post("/api/uploads", formData, config);

        if (data.image) {
          const formatedData = {
            public_id: `${Date.now()}`,
            url: data,
          };

          console.log(formatedData);

        } else {
          dispatch({
            type: UPLOAD_CATEGORY_IMAGE_FAIL,
            payload: data.message,
          });
        }
      } else {
        // Handle the case where no file is selected.
        setErrorMessage("Please select a file.");
      }
    } catch (error) {
      console.error(error);
    }
     };

Extract from server.js:

app.use("/api/uploads", uploadRoutes);

uploadRoutes:


    import path from "path";
    import express from "express";
    import { protect, adminCheck } from "../middleware/authMiddleware.js";
    const router = express.Router();
    import {
      uploadFiles,
      getListFiles,
      getFile,
    } from "../controllers/uploadController.js";

    router.route("/").post(protect, adminCheck, uploadFiles).get(getListFiles);
    router.route("/:filename").get(getFile);

    export default router;

Extract from uploadController.js:

    import asyncHandler from "express-async-handler";
    import uploadFilesMiddleware from "../middleware/uploadMiddleware.js";
    import { MongoClient, GridFSBucket } from "mongodb";
    import getRequestUrl from "../utils/urls.js";

    const mongoClient = new MongoClient(process.env.MONGO_URI);

    const database = mongoClient.db(process.env.DATABASE);

    const image = database.collection(process.env.IMAGE_BUCKET + ".files");

    const bucket = new GridFSBucket(database, {
      bucketName: process.env.IMAGE_BUCKET,
    });

    const uploadFiles = asyncHandler(async (req, res) => {
      try {
        await uploadFilesMiddleware(req, res);
        if (req.file == undefined) {
          return res.send({
        message: "You must select a file.",
      });
      }

       return res.send({
      image: `${req.file.filename}`,
      message: "File has been uploaded.",
    });
      } catch (error) {
       console.log(error);

        return res.send({
          message: "Error when trying upload image: ${error}",
        });
     }
    });

My uploadFilesMiddleware:

    import dotenv from "dotenv";
    import multer from "multer";
    import { GridFsStorage } from "multer-gridfs-storage";
    import util from "util";

    dotenv.config();

    const storage = new GridFsStorage({
      url: process.env.MONGO_URI,
      options: { useNewUrlParser: true, useUnifiedTopology: true },
      file: (req, file) => {
    try {
      const match = ["image/png", "image/jpeg", "image/jpg"];

      if (match.indexOf(file.mimetype) === -1) {
        throw new Error("Invalid file format");
      }
      console.log("image-bucket: ", process.env.IMAGE_BUCKET);
      console.log("upload-file: ", file);
      return {
        bucketName: process.env.IMAGE_BUCKET,
        filename: `${Date.now()}-${process.env.BUSINESS}-${file.originalname}`,
         };
       } catch (error) {
      console.log("error: ", error);
       }
      },
    });

    const uploadFiles = multer({ storage: storage }).single("image");
    const uploadFilesMiddleware = util.promisify(uploadFiles);

    export default uploadFilesMiddleware;

Dependencies and versions extracted from package.json:

"multer": "^1.4.5-lts.1", "multer-gridfs-storage": "^5.0.2",

Full error message:

    C:\Users\streu\OneDrive\Documents\React\foodstore-mern\server\node_modules\multer-gridfs-            storage\lib\gridfs.js:306
    [0]                         id: f._id,
    [0]                               ^
    [0]
    [0] TypeError: Cannot read properties of undefined (reading '_id')
    [0]     at GridFSBucketWriteStream.emitFile (C:\Users\streu\OneDrive\Documents\React\foodstore-    mern\server\node_modules\multer-gridfs-storage\lib\gridfs.js:306:31)  
    [0]     at GridFSBucketWriteStream.emit (node:events:525:35)
    [0]     at finish (node:internal/streams/writable:748:10)
    [0]     at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
    [0]
    [0] Node.js v18.16.1
    [1] Proxy error: Could not proxy request /api/uploads from localhost:3000 to     http://127.0.0.1:5000.
    [1] See https://nodejs.org/api/errors.html#errors_common_system_errors for more information     (ECONNRESET).
    [1]
    [0] [nodemon] app crashed - waiting for file changes before starting...

Please I have spent two days debugging with no headways. Can someone assist here?

I have deleted node_modules and package-lock.js and ran npm install to no avail.

I have tried to dispatch e.target.files[0] to redux action and it did not work.

I checked and find out that all multer-gridfs-storage dependencies are up to date ad are listed in below upject:

    {
      '@types/express': '^4.17.6',
      '@types/mongodb': '^3.5.25',
      '@types/multer': '^1.4.3',
      '@types/pump': '^1.1.0',
      'has-own-prop': '^2.0.0',
      'is-generator': '^1.0.3',
      'is-promise': '^4.0.0',
      'lodash.isplainobject': '>=0.8.0',
      mongodb: '>=2',
      'mongodb-uri': '^0.9.7',
      pump: '^3.0.0'
    }

I tried the same workflow on another application and it worked.


Solution

  • I was having the same issue. I resolved it by changing the mongodb version to 5.9.1