0

I'm creating a book project where i'm saving the books images into the cloudinary and there url's saving into the mongodb database which are working well.But i'm facing issue during the updation of a book when i update my book then the url of book is not updated and console giving me error Cannot read properties of undefined (reading 'map') where i want to update the url with new one url of image but its not working Please any one can solve this

this is my update.js code

module.exports.updateBook = async (req, res) => {
try {
  const { id } = req.params;
  const book = req.body;
  const singleBook = await Book.findById(id);
  // Delete Prvious Url From the Cloudinary and Reset It to the new ..
  cloudinary.v2.uploader.destroy(singleBook.image[0].filename);
  book.image = req.files.map((f) => ({
   url: f.path,
   filename: f.filename,
  }));
   console.log("Single Book ===", singleBook);
   const updateBook = await Book.findByIdAndUpdate(
    id,
    { $set: book },
    { new: true }
   );
  if (updateBook) {
    res
      .status(200)
      .json({ success: true, message: "Book Updated Successfully!" });
  } else {
     res.status(400).json({
     success: false,
     message: "Book Not Updated There Is an error!",
   });
  }
 } catch (err) {
   console.log("** Error In Update Book **", err.message);
 }
};

this is my route handler

const express = require("express");
const router = express.Router();
const book = require("../controller/book");
const authenticated = require("../middleware/verifyToken");
const multer = require("multer");
const { storage } = require("../cloudinary");
const upload = multer({ storage });

// Update Book By ID
router.route("/:id").put(authenticated, upload.array("image"), book.updateBook);
module.exports = router;

this is my reactjs update method

  const formik = useFormik({
   initialValues: {
    title: book?.title,
    author: book?.author,
    price: book?.price,
    description: book?.description,
    image: book?.image[0].url,
  },
validationSchema: validationSchema,
enableReinitialize: true,
    onSubmit: (values) => {
      const formData = new FormData();
      formData.append("title", values.title);
      formData.append("price", values.price);
      formData.append("description", values.description);
      formData.append("author", values.author);
      formData.append("image", values.image);
      Axios.put(`${Base_URL}/book/${id}`, values, {
        headers: {
        Authorization: authHeader(),
       },
      })
       .then((res) => {
        if (res.data.success) {
          message = res.data.message;
          setAlertContentupdate(message);
          setAlertupdate(true);
          setTimeout(() => {
           handleClose();
             navigate(`/book/${id}`);
           getBook();
           console.log("Response == ", res.data.message);
          }, 3000);
        }
      })
      .catch((err) => {
        console.log("Error ====", err.message);
       });
     },

this is my jsx code for updating book

 <form onSubmit={formik.handleSubmit}>
          <TextField
            name="title"
            autoFocus
            margin="dense"
            label="Book Title"
            type="text"
            fullWidth
            variant="standard"
            value={formik.values.title}
            onChange={formik.handleChange}
            error={formik.touched.title && Boolean(formik.errors.title)}
            helperText={formik.touched.title && formik.errors.title}
          />
          <TextField
            name="author"
            margin="dense"
            label="Book Author"
            type="text"
            fullWidth
            variant="standard"
            value={formik.values.author}
            onChange={formik.handleChange}
            error={formik.touched.author && Boolean(formik.errors.title)}
            helperText={formik.touched.author && formik.errors.author}
          />
          {/* File Input Field */}
          {/* Picture Input */}
          <input
            type="file"
            name="image"
            accept=".png, .jpeg, .jpg"
            onChange={(e) => {
              formik.setFieldValue("image", e.target.files[0]);
            }}
          />
          {formik.touched.image && formik.errors.image ? (
            <div style={{ color: "#e53935", fontSize: "12px" }}>
              {formik.errors.image}
            </div>
          ) : null}
          {/* Price Input Field */}
          <TextField
            name="price"
            margin="dense"
            label="Book Price"
            type="text"
            fullWidth
            variant="standard"
            value={formik.values.price}
            onChange={formik.handleChange}
            error={formik.touched.price && Boolean(formik.errors.price)}
            helperText={formik.touched.price && formik.errors.price}
          />
          <TextField
            name="description"
            margin="dense"
            label="Book Description"
            type="text"
            fullWidth
            variant="standard"
            value={formik.values.description}
            onChange={formik.handleChange}
            error={
              formik.touched.description &&
              Boolean(formik.errors.description)
            }
            helperText={
              formik.touched.description && formik.errors.description
            }
          />
          <DialogActions>
            <Button onClick={handleClose}>Cancel</Button>
            <Button type="submit">Update</Button>
          </DialogActions>
        </form>

In formik i'm getting the book data from back end api's and putting into the formik initial values But Problem is that when i clicked on the update button then the backend compiler giving me this error Cannot read properties of undefined (reading 'map') Please any one can solve this thanks in advance

Amir Shahzad
  • 182
  • 2
  • 10

1 Answers1

5

So this line looks like the issue for me:

cloudinary.v2.uploader.destroy(singleBook.image[0].filename);

Using this is actually deleting your asset so you are probably want to just update it using the explicit API. See https://cloudinary.com/documentation/image_upload_api_reference#explicit

So maybe something like:

cloudinary.v2.uploader.explicit(singleBook.image[0].filename);

Let me know if this helps?

Tom
  • 101
  • 4
  • thanks for your precious answer but my problem is that when i not select any file in my update form and update others book items then my image url destroy and nothing shown on my home screen – Amir Shahzad Mar 22 '22 at 08:48
  • is there any way if i not select any image in my update form then my previous image still same as it was – Amir Shahzad Mar 22 '22 at 08:50
  • 1
    In that case, you should probably add a check in your react.js file to validate whether the user selected a file so the `Update` should only execute when a file is selected. See https://stackoverflow.com/questions/46219/how-to-determine-if-user-selected-a-file-for-file-upload, hope this helps. – Tom Mar 22 '22 at 14:04
  • Good it's right – Amir Shahzad Mar 22 '22 at 15:48