DEV Community

Cover image for Day 60 of Learning MERN Stack
Ali Hamza
Ali Hamza

Posted on

Day 60 of Learning MERN Stack

Hello Dev Community! 👋

It is officially Day 60 — a massive 2-month milestone on my unbroken daily sprint toward mastering full-stack software engineering! Yesterday, I streamed PDFs using Node chunks. Today, I solved a critical storage management flaw that separates junior codebases from production-grade systems: Automated Image Cleanup and File System Overwrites during Database Updates!

When a host or user updates a product listing with a fresh image upload, the old file turns into dead server junk. If you don't clear it out, your server disk will slowly run out of space. Today, I engineered a self-cleaning file mutation pipeline to automate this entire process!


🧠 Key Learnings From Day 60 (File System Mutations & Overwrites)

Handling file mutations securely requires strict fallback checking and utilizing non-blocking asynchronous file operations:

1. The Dynamic Image Mutation Logic

Inside my edit controller, I learned to execute a conditional check on the inbound req.file payload stream:

  • Scenario A (New Image Uploaded): The server captures the new path, fetches the old document data to locate the previous file path, triggers an asynchronous file delete on the old asset, and saves the fresh image reference to the DB.
  • Scenario B (No New Image Uploaded): The server falls back gracefully onto the existing database image path string, ensuring unchanged listings don't get cleared or corrupted.

2. Asynchronous Garbage Collection via fs.unlink

Instead of keeping dead files around, I used Node's native fs.unlink() module. By supplying the precise relative asset path, Express clears the old physical file out of the public/images folder the exact moment the new Mongoose transaction resolves:


javascript
const fs = require('fs');
const path = require('path');
const Home = require('../model/home');

exports.postEditHome = async (req, res, next) => {
    const { homeId, title, price, description } = req.body;
    const image = req.file; // Capturing the potential multi-part stream

    try {
        const home = await Home.findById(homeId);
        let imageUrl = home.photoUrl; // Defaulting to original file path

        if (image) {
            // A new image came through! Time to clear the legacy asset junk
            if (home.photoUrl) {
                fs.unlink(home.photoUrl, (err) => {
                    if (err) console.log("File cleanup skipped or missing:", err);
                });
            }
            imageUrl = image.path; // Overwriting with the fresh asset destination path
        }

        // Updating the database properties smoothly
        home.houseName = title;
        home.price = price;
        home.description = description;
        home.photoUrl = imageUrl;

        await home.save();
        res.redirect('/host/homes');
    } catch (err) {
        console.log(err);
    }
};
Enter fullscreen mode Exit fullscreen mode

Top comments (0)