Home > Back-end >  issue with uploading and retriving images to mongoDB using express
issue with uploading and retriving images to mongoDB using express

Time:02-24

I am building a beginner fullstack project where I am making a webstore. On here I have an admin route where I can upload new products to my mongoDB database so they get displayed on the store. Like any good webstore, I need images to show off my product, but I am having a hard time writing the code for that feature. I know there is something called GridFS, however my images will never exceed 16 MB so I dont want to overcomplicate my solution.

See the comments below the arrow in my code for the specific problem I am having

Schema for my products:

const mongoose = require("mongoose");

const UserSchema = new mongoose.Schema({
  productName: {type: String, required: true, unique: true},
  image: {data: Buffer, contentType: String},
  price: {type: Number, required: true}
}, {timestamps: true});

module.exports = mongoose.model("Product", UserSchema);

Add new product route:

const router = require("express").Router();                       //
const Product = require("../models/Product");                     //
                                                                  //
router.post("/add", async (req, res) => {                    //   //   //
  const newProduct = new Product({                             // / //
    productName: req.body.productName,                           //
    image: {                   // this is where I have no idea what I am doing
      data: req.body.image,    // req.body.image is just the filename, do I need the entire path?
      contentType: 'image/png' // not all images are png, how do I update this depending on image type?
    },
    price: req.body.price
  });
  try {
    const savedProduct = await newProduct.save();
    res.redirect("../products");
  } catch (err) {
    console.log(err);
    console.log("an error occured when adding product");
    res.redirect(400, "../products");
  }
});

Display products page:

<% products.forEach(product => { %>
  <article>
    <h2><%= product.productName %></h2>
    <div ><%= product.price %></div>
    <img src="<%= product.image %>" alt="">
  </article>
<% }) %>

CodePudding user response:

You can use a middleware package like express-fileupload to handle file uploads. Here is the documentation for the package Link.

Assuming the name of the input for the image is image, you can access the image's information from req.files.image. This object contains the file represented in a buffer and its mimetype. Now you can store these two information in the database like this:

router.post("/add", async (req, res) => {
  const img = req.files.image;
  
  const newProduct = new Product({
    productName: req.body.productName,
    image: {
      data: img.data,  // buffer
      contentType: img.mimetype
    },
    price: req.body.price
  });

  try {
    const savedProduct = await newProduct.save();
    res.redirect("../products");
  } catch (err) {
    console.log(err);
    console.log("an error occured when adding product");
    res.redirect(400, "../products");
  }
});

When you want to display this image on the html page, you have to convert the buffer to a base64 representation. You can simply use .toString("base64") on the buffer data retrieved from the database. The value of src should be in this format data:[<mediatype>][;base64],<data> referance:

<% products.forEach(product => { %>
  <article>
    <h2><%= product.productName %></h2>
    <div ><%= product.price %></div>
    <img src="data:<%= product.image.contentType%>;base64,<%= product.image.data.toString('base64')%>" alt="">
  </article>
<% }) %>

I haven't tried this but if the code in the ejs file throw an error, try storing the image in base64 encoding in the database, then use the product.image.data directly in the ejs file

  • Related