0

I wrote the following code to create a formatted JSON file that holds all names of files (testfile1, testfile2, testfile3) that exist in a directory called "uploads".

const fs = require("fs");
let toJson = {files: []};
let file = new Object();

function createJSON(){
fs.readdir("./uploads", (err, files) => {

//add each files name to obj
files.forEach((item, index) => {
  file.name = item;
  console.log(index, item);

  toJson.files.push(file);
});
var saveJson = JSON.stringify(toJson, null, 4);

fs.writeFile('./files.json', saveJson, 'utf8', (err) => {
  if(err) throw err;
  console.log(err);
});
});
}

The output from console.log(item, index) is as expected:

0 testfile1
1 testfile2
2 testfile3

However, the JSON file that is being created holds the following names:

{
"files": [
    {
        "name": "testfile3"
    },
    {
        "name": "testfile3"
    },
    {
        "name": "testfile3"
    }
]
}

instead of the intended

{
"files": [
    {
        "name": "testfile1"
    },
    {
        "name": "testfile2"
    },
    {
        "name": "testfile3"
    }
]
}
Mike
  • 23
  • 3
  • 2
    There is only one object used and reused. On each iteration, the code overwrites the property of the object stored in `file`, it does not create a new object. Get rid of `file` and try `toJson.files.push({name: item});` – axiac May 15 '21 at 13:08

3 Answers3

0

Your problem lies in your memory referencing. In the following code, you are setting the name of the file and pushing the file to an array. However, you are not pushing the item to the array, you are pushing the reference of the item to the array. This means that on subsequent iterations, you are changing the attributes of the elements that are in the array as well.

files.forEach((item, index) => {
  file.name = item;
  console.log(index, item);

  toJson.files.push(file);
});

See an example below of these memory issues.

const array = [];
const item = {};

item.name = 5;

array.push(item);

item.name = 4;

console.log(array);

const copy = Object.assign({}, item);

copy.name = 3;

array.push(copy);

item.name = 6;

console.log(array);

To fix this, you need to create a copy of the object at each step. There should be enough information in this post to assist you with this: What is the most efficient way to deep clone an object in JavaScript?

An example of fixed code would be the following:

files.forEach((item, index) => {
  const f = Object.assign({}, file);
  f.name = item;
  console.log(index, item);

  toJson.files.push(f);
});
Hive7
  • 3,599
  • 2
  • 22
  • 38
0

You are not changing the file object inside your forEach loop. You are only changing its name property. That's why you end up with all the same file names

Just move the line file = new Object() or file = {} to the beginning of the forEach loop

devnull69
  • 16,402
  • 8
  • 50
  • 61
0

You should be calling synchronously. You are also overwriting the same object. You can greatly simplify your code.

const fs = require("fs");

function createJSON(){
    const files = fs.readdirSync("./uploads").map((file, index) => {
        console.log(index, file)
        return {
            name: file
        }
    });

    const output = JSON.stringify({
        files
    }, undefined, 4)

    
    fs.writeFileSync('./files.json', output)
}
Andrew Gillis
  • 3,250
  • 2
  • 13
  • 15