Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON data returns {} without any data

var getfiles = function (context) {

  var scriptPath = '/var/names/myfolder';
  fs.readdir(scriptPath, function (err, files) {
    if (err) return context.sendJson(err, 404);
    var resultingJson = {};
    for (var j = 0; j < files.length; j++) {
      subfolder = scriptPath + files[j];
      console.log(files[j]);// prints art,creation
      fs.readdir(subfolder, function (err, fi) {

                //fi prints [artdetails.txt,artinfo.txt]
                        // [creationdetails.txt,create.txt]    
          //  console.log(files[j]);// prints undefined here

        resultingJson[files[j]] = fi;

      });

    }
    console.log(resultingJson); // returing {}

    context.sendJson(resultingJson, 200);
  });
}

Above code is used to fetch files inside subfolder myfolder, it contains art,creation and inside this art folder contains files artdetails.txt,artinfo.txt creation folder contains files creationdetails.txt,create.txt etc.

Folder and files are fetching successfully but I want to generate a JSON format like this:

{`art':['artdetails',artinfo],'creation':['creationdetails','create']} format

How it is possible?

I used resultingJson[files[j]] = fi; but it returns{}.

What is wrong with my code?

like image 936
Sush Avatar asked Oct 21 '22 14:10

Sush


2 Answers

You care resetting the value of resultingJson to {} inside a recursive function.

try this code

var getfiles = function (context) {

  var scriptPath = '/var/names/myfolder';
  var resultingJson = {};
  fs.readdir(scriptPath, function (err, files) {
    if (err) return context.sendJson(err, 404);
    for (var j = 0; j < files.length; j++) {
      subfolder = scriptPath + files[j];
      console.log(files[j]);// prints art,creation
      fs.readdir(subfolder, function (err, fi) {

                //fi prints [artdetails.txt,artinfo.txt]
                        // [creationdetails.txt,create.txt]    
          //  console.log(files[j]);// prints undefined here

        resultingJson[files[j]] = fi;

      });

    }
    console.log(resultingJson); // returing {}

    context.sendJson(resultingJson, 200);
  });
}
like image 198
SajithNair Avatar answered Oct 23 '22 04:10

SajithNair


There are a few problems here. First and foremost, Felix Kling made the correct observation about readdir being async, more specifically referring to the inner readdir within the for loop. Part of what you are seeing is that your console.log and JSON response is occurring before the directories have finished being read. Also what is likely occurring is the context of j is being lost, likely ending up the last value.

A control flow library like async may help, such as the each method.

var fs = require('fs'),
    async = require('async');

var scriptPath = '/var/names/myfolder';

var getfiles = function(context) {
  // Read contents of the parent directory
  fs.readdir(scriptPath, function(err, files) {
    if (err) return context.sendJson(err, 404);
    var result = {};
    // Asynchronously iterate over the directories
    async.each(files, function iterator(directory, next){
      var subfolder = scriptPath + directory;
      // Read contents of the child directory
      fs.readdir(subfolder, function(err, file){
        if (err) return next(err);
        // Set the property
        result[directory] = file;
        // Now that we've finished reading these contents,
        // lets read the contents of the next child folder
        next();
        // When there are none left, the `complete` callback will
        // be reached and then it is safe to return a JSON string
      });
    }, function complete(err){
      // All children directories have been read
      // and the `result` object should be what we expect
      if (err) return context.sendJson(err, 404);
      context.sendJson(result, 200);
    });
  });
};

I have tested this by mocking your folder/file structure and it appears to work properly. It produced the following JSON string:

{"art":["artdetails.txt","artinfo.txt"],"creation":["create.txt","creationdetails.txt"]}

The iterators are called in parallel, so the order may switch, but it shouldn't make a difference.

like image 38
Kevin Reilly Avatar answered Oct 23 '22 04:10

Kevin Reilly