I am creating the backend server for a ecommerce website. I handle file uploads with multer and store them in gridfs. Now, when updating a new product, not all images may be submitted to be updated. I need a way to identify what field was updated, so I can delete the current file and upload the new file to mongodb. I've reached the point where I think it's impossible, but I'm still trying. Are there any alternative approach I could take. All responses are greatly appreciated.
Here is the code for the router and the 3 middleware functions I call when a request is made to said route.
```
router
.route("/:id")
.put(
productController.readPhotos,
productController.appendPhotoOnRequestBody,
productController.updateProduct
)
exports.readPhotos = upload.fields([
{ name: "coverPhoto", maxCount: 1 },
{ name: "colorPhoto", maxCount: 4 },
]);
exports.appendPhotoOnRequestBody = asyncHandler(async (req, res, next) => {
req.addedFiles = [];
if (
req.originalUrl === "/api/products" &&
req.method === "POST" &&
!req.files
) {
// Error message to send to user if the above condition is true.
const message = `To create a new product, a coverPhoto and at least one color with a colorPhoto must be specified`;
return next(new AppError(400, message));
} else if (!req.files) next();
if (req.files?.coverPhoto) {
// Extract coverPhoto
const [coverPhoto] = req.files.coverPhoto;
// Process images
const coverPhotoBuffer = await processImage(coverPhoto.buffer, [300, 300]);
// Pushing the coverPhoto to the db
const coverPhotoStream = Readable.from(coverPhotoBuffer);
const coverPhotoValue = await pushToDbFromStream(
coverPhotoStream,
req,
coverPhoto
);
req.body.coverPhoto = coverPhotoValue.filename;
req.addedFiles.push(req.body.coverPhoto);
}
if (req.files?.colorPhoto) {
// Extract colorPhotos
const colorPhotos = [...req.files.colorPhoto];
const colorPhotoBuffers = await Promise.all(
colorPhotos.map((photo) => processImage(photo.buffer, [50, 50]))
);
// Pushing the colorPhotos to the db
const colorPhotosStreams = colorPhotoBuffers.map((buff) =>
Readable.from(buff)
);
const colorPhotoValues = await Promise.all(
colorPhotosStreams.map((stream, index) =>
pushToDbFromStream(stream, req, colorPhotos[index])
)
);
req.body.colors = JSON.parse(req.body.colors);
colorPhotoValues.forEach((value, index) => {
req.body.colors[index].colorPhoto = value.filename;
});
req.body.colors.forEach((color) => req.addedFiles.push(color.colorPhoto));
}
next();
});
exports.updateProduct = asyncHandler(async (req, _, next) => {
req.product = await Product.findByIdAndUpdate(req.params.id, req.body, {
runValidators: true,
new: true,
});
next();
});
exports.updateProduct = asyncHandler(async (req, _, next) => {
req.product = await Product.findByIdAndUpdate(req.params.id, req.body, {
runValidators: true,
new: true,
});
next();
});
```
CodePudding user response:
What I have done is upload new images, then merge these images with the images that are in MongoDB, and update the document with the images merged.
In this case, you are not querying the product first to obtain the images previously added.
I consider it necessary because MongoDB will replace the images previously added if you only send the new images.
CodePudding user response:
There is a reference to the images in a color property of the product Schema. That uses the embedded document style. Instead, I could use the referenced way instead, and create new Color documents and update them individually.