tejazz / gridfs-file-storage

GridFS file storage enabled application to store and retrieve files and images.
51 stars 39 forks source link

Question : how do you update a file? #8

Closed weirdyang closed 3 years ago

weirdyang commented 3 years ago

What is the recommended approach to update a file?

tejazz commented 3 years ago

Updating a file in GridFS is slightly more tricky. The accepted way is to delete the file you are updating and then re-add it. Let me check if there is a better way possible.

weirdyang commented 3 years ago

Thanks! I read from the docs that using binData is recommended if atomic transactions are needed, and if the file size is small. I will look into that instead.

tejazz commented 3 years ago

I have not tried that. But if you do, can you share the approach in this thread?

weirdyang commented 3 years ago

models/product.js

const productSchema = new mongoose.Schema({
  name: {
    type: String,
    lowercase: true,
    required: [true, 'this can not be blank'],
    unique: true,
    minLength: [6, 'Product name needs to be at least 6 characters'],
    trim: true,
    index: true,
  },
  description: {
    type: String,
    required: [true, 'this can not be blank'],
    unique: false,
    minLength: [6, 'Product description needs to be at least 6 characters'],
  },
  productType: {
    type: mongoose.Types.ObjectId, required: true, ref: 'ProductType',
  },
  image:
  {
    data: Buffer,
    contentType: String,
  },
  user: { type: mongoose.Types.ObjectId, required: true, ref: 'User' },
}, { timestamps: true });

product.controller.js

const uploadStrategy = multer(
  {
    storage: inMemoryStorage,
    fileFilter,
    limits: {
      fileSize: MAX_SIZE,
    },
  },
).single('file');

const createProduct = async (req, res, next) => {
  const result = validationResult(req).formatWith(errorFormatter);
  if (!result.isEmpty()) {
    debug(result);
    debug(result.errors);
    return next(new HttpError('Invalid inputs', 422, result.array()));
  }
  let newProduct;
  try {
    newProduct = new Product({
      name: req.body.name,
      user: req.user.id,
      description: req.body.description,
      image: {
        data: req.file.buffer,
        contentType: req.file.mimetype,
      },
    });
    await newProduct.save();
    return res.status(200).send({ message: `${newProduct.name} saved`, product: newProduct });
  } catch (error) {
    debug(error);
    return handleError(error, next);
  }

const updateProduct = async (req, res, next) => {
  const result = validationResult(req).formatWith(errorFormatter);
  if (!result.isEmpty()) {
    debug(result);
    return next(new HttpError('Invalid inputs', 422, result.array()));
  }
  try {
    const { name, description } = req.body;
    const productId = mongoose.Types.ObjectId(req.params.id);
    const product = await Product.findOneAndUpdate(
      { _id: productId },
      {
        name,
        description,
        user: req.user.id,
        image: {
          data: req.file.buffer,
          contentType: req.file.mimetype,
        },
      },
      { new: true },
    );
    return res.json({ product, id: req.user.id });
  } catch (error) {
    return handleError(error, next);
  }
};

products.router.js

// create new product
router.post('/create', uploadStrategy, reqChecks, createProduct);

// update product entry
router.put('/:id', uploadStrategy, reqChecks, updateProduct);
tejazz commented 3 years ago

This is interesting. Thank you so much for the update.

tejazz commented 3 years ago

Marking it as closed for now. Let me know if we need to do anything else here.