1

I'm reading a list of filenames from items in a MongoDB server and then checking if any of those filenames exist on local storage. I'm trying to create a list of all the matching filenames, the ones that exist both locally and in the database, and then send that list in an Express response.

Here's what I've come up with.

app.get('/api/album', (req, res) => {
  let matches = [];

  Album.find({}).then(albums => {
    albums.forEach( (item,  index) => {

      fs.readdir('./static/img/album-art/', (err, files) => {
        files.forEach(file => {
          if (file !== undefined && item.coverUrl !== undefined) {

            if (file == item.coverUrl) {
                matches.push(item.name);
            }
          }
        });
      });
    });
  });

  res.json(matches);
});

However, the response only contains an empty list because fs.readdir() is asynchronous. I'd like to keep it asynchronous, but I'm trying to find a way to send the response after it's complete. I'm not great with promises, and I know I can use async/await here but I haven't been able to get it to work.

Grav
  • 461
  • 6
  • 18
  • Does this answer your question? [Using filesystem in node.js with async / await](https://stackoverflow.com/questions/40593875/using-filesystem-in-node-js-with-async-await) – Juhil Somaiya Mar 02 '20 at 07:52

3 Answers3

1

You can use the built-in promise support for the fs library and also to avoid doubly nested loop, you can put the list of files in a Set for more efficient checking against every item:

const fsp = require('fs').promises;

app.get('/api/album', async (req, res) => {
  let matches = [];

  try {
      let albums = await Album.find({});
      let files = await fsp.readdir('./static/img/album-art/');
      let filesSet = new Set(files);
      let matches = [];
      for (let item of albums) {
          if (filesSet.has(item.coverUrl)) {
              matches.push(item.name);
          }
      }
      res.json(matches);
  } catch(e) {
      console.log(e);
      res.sendStatus(500);
  }
});

Based on your code, I'm assuming that the item.coverUrl is actually just a base filename like mysong.jpg, not an actual URL because an actual fully qualified URL will never match one of the filenames.

FYI, you don't need either of the undefined checks. The files array will never contain undefined values so even if item.coverUrl is undefined, it will never match one of the files so it kinds of takes care of itself in that way as it will just never match.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
0

"util" library should do the trick as suggested by below answer.

Using filesystem in node.js with async / await

0

You can use readdirSync() which is synchronous way to read a directory.

Raj Saraogi
  • 1,780
  • 1
  • 13
  • 21
  • Synchronous I/O is never recommended in a server request handler because it blocks the event loop and ruins server scalability. It is only appropriate for server startup code or non-server scripts where it doesn't matter if you block the whole event loop. – jfriend00 Mar 02 '20 at 06:35