1

Hello All!

I want to store users in folder as a file where file name is equal to user_id.

data
| - users
      | - afdcab7e-b595-4a15-be0f-5f0337bd1317.json
      | - fdfacb7i-bk00-4a15-be0f-5f0337b1d991.json

Each user has their own data for example

{
    "_id": "afdcab7e-b595-4a15-be0f-5f0337bd1317",
    "email": "test1@test.pl",
    "password": "$2a$12$nIoudV7eXmJbU7e/P6YCbOccUkTbp8tcQKhyCEfmNOLihrW6QqPTC"
}
{
    "_id": "fdfacb7i-bk00-4a15-be0f-5f0337b1d991",
    "email": "test2@test.pl",
    "password": "$2a$12$nIoudV7eXmJbU7e/P6YCbOccUkTbp8tcQKhyCEfmNOLihrW6QqPTC"
}

Then I want to read the contents of all files and put the objects into one temporary array.

exports.indexSignin = (req, res) => {

    fs.readdir('./data/users', (err, files) => {
        if (err) console.log(err);

        const obj = [];
        files.map((file) => {
            fs.readFile(`./data/users/${file}`, 'utf-8', (err, data) => {
                if (err) console.log(err);
                obj.push(JSON.parse(data))
                console.log(obj)
            });
        });
        console.log(obj) //There obj is empty but I want an array
    });

    res.render('./index/index');
});

As an output I want to have an array saved into variable like this listed below:

[
{
    "_id": "afdcab7e-b595-4a15-be0f-5f0337bd1317",
    "email": "test1@test.pl",
    "password": "$2a$12$nIoudV7eXmJbU7e/P6YCbOccUkTbp8tcQKhyCEfmNOLihrW6QqPTC"
},
{
    "_id": "fdfacb7i-bk00-4a15-be0f-5f0337b1d991",
    "email": "test2@test.pl",
    "password": "$2a$12$nIoudV7eXmJbU7e/P6YCbOccUkTbp8tcQKhyCEfmNOLihrW6QqPTC"
}
]

Do you have any ideas how to use mapped data externally or refactor it into a better way?

ownidea
  • 63
  • 7
  • I don't understand the question. Can you provide example input and output data? What does _"use mapped data externally"_ mean? – jabaa Dec 17 '21 at 20:08
  • @jabaa I've edited my question and add some more details. – ownidea Dec 17 '21 at 20:20
  • Isn't that the content of `obj`? – jabaa Dec 17 '21 at 20:23
  • @jabaa I marked another console.log where I want to use obj variable and there is an empty array in it. – ownidea Dec 17 '21 at 20:27
  • 1
    Does this answer your question? [How to return the response from an asynchronous call](https://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) – jabaa Dec 17 '21 at 20:29
  • @jabaa It seems to be very similar, but I had no problems reading one file. In this situation, I want to get data from several files using the mapping method. – ownidea Dec 17 '21 at 21:04
  • There is no difference between one file and multiple files. `fs.readFile` is an asynchronous function. The callback is executed after `console.log(obj)`. – jabaa Dec 17 '21 at 21:05

2 Answers2

1

Thank You guys! I solved my problem with Your help.

Here is a working example which I needed:

exports.indexSignin = (req, res) => {

    const readFiles = async () => {
        try {
            const path = "./data/users"
            const files = await readdir(path);
    
            const fileAwaits = files.map(file => readFile(`${path}/${file}`, "utf8"))
            const contents = await Promise.all(fileAwaits)
            return contents.map(co => JSON.parse(co))
        } catch (err) {
            throw err;
        }
    }

    readFiles()
        .then(test => console.log(test))
        .catch(err => console.log('Directory not found.'))
        .finally(() => console.log('Rest of the code...'));

    res.render('./index/index');


    // or IIFY which do the same 
    (async () => {
        try {
            const test = await readFiles();
            console.log(test);
        } catch (err) {
            console.log('Directory not found.');
        }
        console.log('Rest of the code...')
        res.render('./index/index');
    })()
};
ownidea
  • 63
  • 7
0

This is the same code of mine that works. I hope that helps you.

const { readdir, readFile } = require("fs/promises");

const readFiles = async () => {
    try {
        const path = "./test"
        const files = await readdir(path);
        console.log(files)

        const fileAwaits = files.map(file => readFile(`${path}/${file}`, "utf8"))
        const contents = await Promise.all(fileAwaits)
        console.log(contents.map(co => JSON.parse(co)))
    } catch (err) {
        console.error(err)
    }
}

readFiles()

So if you want to use this inside your API handlers change it as bellow:

exports.indexSignin = async (req, res) => {

    try {
        const path = "./test" // replace path by your own
        const files = await readdir(path);
        console.log(files)

        const fileAwaits = files.map(file => readFile(`${path}/${file}`, "utf8"))
        const contents = await Promise.all(fileAwaits)
        const arrayContent = contents.map(co => JSON.parse(co))
        console.log(arrayContent);
    } catch (err) {
        console.error(err)
    }
    res.render('./index/index');
});
Heartbit
  • 1,698
  • 2
  • 14
  • 26
  • It works similar to my example but it's not solving my problem. I want to store `console.log(contents.map(co => JSON.parse(co)))` into a variable and use it somehow in other place e.g after readFiles function is called. – ownidea Dec 17 '21 at 22:44