'NodeJs - Get last modified file in sub directories of directory

I have the following code to list all folders within a directory, and it maps each folder's name and date created. I'm struggling to get the last modified file within the sub directories of the folders.

const fs = require('fs')
const glob = require("glob")

const getDirectories = (source, callback) => {

    const getDirectories = function (src, callback) {
        glob(src + '/*/*/*', callback)
    }

    fs.readdir(source, { withFileTypes: true }, (err, files) => {
        if (err) {
            callback(err)
        } 
        else {
            callback(
                files
                .filter(dirent => dirent.isDirectory())
                .map(name => ({
                    name: name.name,
                    created: fs.statSync(`${source}\\${name.name}`).birthtime.toLocaleString(navigator.language, {
                            day: '2-digit',
                            month: 'short',
                            year: '2-digit',
                            hour: '2-digit',
                            minute: '2-digit'
                        }
                    ),
                    modified: getDirectories(`${source}\\${name.name}`, function (err, res) {
                        res = res.map(file => ({ file, mtime: fs.lstatSync(file).mtime }))
                        .sort((a, b) => b.mtime - a.mtime)
                        return res.length ? res[0] : ''
                    })
                }))
                .sort(function (a, b) {
                    if ($sort == 1) {
                        if (a.name < b.name) return -1;
                        if (a.name > b.name) return 1; 
                        return 0;
                    }
                    else if ($sort == 2) {
                        if (a.name > b.name) return -1;
                        if (a.name < b.name) return 1; 
                        return 0;
                    }
                    else if ($sort == 3) {
                        if (a.created < b.created) return -1;
                        if (a.created > b.created) return 1; 
                        return 0;
                    }
                    else if ($sort == 4) {
                        if (a.created > b.created) return -1;
                        if (a.created < b.created) return 1; 
                        return 0;
                    }
                    else if ($sort == 5) {
                        if (a.modified < b.modified) return -1;
                        if (a.modified > b.modified) return 1; 
                        return 0;
                    }
                    else if ($sort == 6) {
                        if (a.modified > b.modified) return -1;
                        if (a.modified < b.modified) return 1; 
                        return 0;
                    }
                })
            )
        }
    })
}

My problem is with the follwing snippet:

modified: getDirectories(`${source}\\${name.name}`, function (err, res) {
                    res = res.map(file => ({ file, mtime: fs.lstatSync(file).mtime }))
                    .sort((a, b) => b.mtime - a.mtime)
                    return res.length ? res[0] : ''
                })

I'm struggling to get a return value to set the modified object. If I do console.log(res) I can see that I get the expected result

I'm listing all the folders in HTML with the name, created and modified properties.

An example of the directories:

Working Dir
├──Work Space1
   └──Category1
      └──Location_a
         └── *.file_a1
         └── *.file_a2
         └── *.file_a3
      └──Location_b
         └── *.file_b1
         └── *.file_b2
         └── *.file_b3
   └──Category2
      └──Location_a
         └── *.file_a1
         └── *.file_a2
         └── *.file_a3
      └──Location_b
         └── *.file_b1
         └── *.file_b2
         └── *.file_b3
├──Work Space2
   └──Category1
      └──Location_a
         └── *.file_a1
         └── *.file_a2
         └── *.file_a3
      └──Location_b
         └── *.file_b1
         └── *.file_b2
         └── *.file_b3
   └──Category2
      └──Location_a
         └── *.file_a1
         └── *.file_a2
         └── *.file_a3
      └──Location_b
         └── *.file_b1
         └── *.file_b2
         └── *.file_b3

I need to get the last modified file of each file within each Work Space regardless of the sub folders

And example of the HTML output:

enter image description here



Solution 1:[1]

try with recursive function, add stats you need, then you can sort the results.

check the code (directory path is included so you could work out hierarchy if needed (credits for reading files solution: Smally's answer)):

const getDirectories = (source) => {

    const files = [];

    function getFiles(dir) {

        fs.readdirSync(dir).map(file => {

            const absolutePath = path.join(dir, file);

            const stats = fs.statSync(absolutePath);

            if (fs.statSync(absolutePath).isDirectory()) {

                return getFiles(absolutePath);

            } else {
                const modified = {
                    name: file,
                    dir: dir,
                    created: stats.birthtime.toLocaleString(navigator.language),
                    modified: stats.mtime
                };
                return files.push(modified);
            }
        });
    }

    getFiles(source);
    return files;
}


const files = getDirectories(somePath);

console.log('\ngot files:', files.length);

// sort...
const lastModified = files.sort((a, b) => b.modified - a.modified);

console.log('\nlast modified:\n', lastModified[0]);

Solution 2:[2]

Thanks to traynor's answer I got it working. Had to make some changes to make it work for my use case.

Full code:

const getDirectories = (source, callback) => {

    const getAllFiles = (dir) => {
        let files = [];

        const getFiles = (dir) => {
            fs.readdirSync(dir).map(file => {
                const absolutePath = path.join(dir, file)
                const stats = fs.statSync(absolutePath)
                
                if (fs.statSync(absolutePath).isDirectory()) {
                    return getFiles(absolutePath)
                }
                else {
                    let modified = stats.mtime
                    
                    return files.push(modified)
                }
            })
        }

        getFiles(dir)
        return files.slice(1)
    }

    const getLastModified = (dir) => {
        let files = getAllFiles(dir)

        files = files.sort((a, b) => b - a)
        return files[0]
    }

    fs.readdir(source, { withFileTypes: true }, (err, files) => {
        if (err) {
            callback(err)
        } 
        else {
            callback(
                files
                .filter(dirent => dirent.isDirectory())
                .map(name => ({
                    name: name.name,
                    created: fs.statSync(`${source}\\${name.name}`).birthtime.toLocaleString(navigator.language, {
                            day: '2-digit',
                            month: 'short',
                            year: '2-digit',
                            hour: '2-digit',
                            minute: '2-digit'
                        }
                    ),
                    modified: getLastModified(`${source}\\${name.name}`).toLocaleString(navigator.language, {
                            day: '2-digit',
                            month: 'short',
                            year: '2-digit',
                            hour: '2-digit',
                            minute: '2-digit'
                        }
                    )
                }))
                .sort(function (a, b) {
                    if ($sort == 1) {
                        if (a.name < b.name) return -1;
                        if (a.name > b.name) return 1; 
                        return 0;
                    }
                    else if ($sort == 2) {
                        if (a.name > b.name) return -1;
                        if (a.name < b.name) return 1; 
                        return 0;
                    }
                    else if ($sort == 3) {
                        if (a.created < b.created) return -1;
                        if (a.created > b.created) return 1; 
                        return 0;
                    }
                    else if ($sort == 4) {
                        if (a.created > b.created) return -1;
                        if (a.created < b.created) return 1; 
                        return 0;
                    }
                    else if ($sort == 5) {
                        if (a.modified < b.modified) return -1;
                        if (a.modified > b.modified) return 1; 
                        return 0;
                    }
                    else if ($sort == 6) {
                        if (a.modified > b.modified) return -1;
                        if (a.modified < b.modified) return 1; 
                        return 0;
                    }
                })
            )
        }
    })
}

Call it with:

let workSpaces

getDirectories(workSpaceDir, (dirs) => {
   workSpaces = dirs
})

This will return an array with objects name, created and modified.

As for the whole block of

.sort(function (a, b) {
    if ($sort == 1) {
       if (a.name < b.name) return -1;
       if (a.name > b.name) return 1; 
       return 0;
    }...
})

...I have a <select/> that sets $sort (witch is a svelete store) the id of the option selected. This will sort the workSpaces array accordingly.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 traynor
Solution 2 marc_s