Подтвердить что ты не робот

Создание массива объектов из разобранных CSV файлов в node

У меня есть несколько CSV файлов формы

  • model1A
  • model1B
  • model2A
  • model2B

где каждый csv представляет собой массив, т.е. model1A = [1, 1, 1]

Я хочу проанализировать эти csvs и создать единый массив, содержащий все эти модели, где каждый элемент в массиве является объектом, соответствующим одной конкретной модели, т.е.

finalArray = [ 
  { 
    "model" :   "model1",
    "A"     :   [1, 1, 1],
    "B"     :   [2, 2, 2]
  },
  { 
    "model" :   "model2",
    "A"     :   [3, 3, 3],
    "B"     :   [4, 4, 4]
  }
]

Код, который у меня есть до сих пор,

var csv = require('csv');
var fs = require('fs');
var parser = csv.parse();
var util = require('util');
var junk = require('junk');
var _ = require('lodash');
var models = [];


fs.readdir(__dirname+'/data', function(err, files) {
    var model = {};
    _.forEach(files, function(n, key) {

        console.log('Analysing file: ' + n);
        var modelName;
        var modelNum;
        var modelParam;


        modelNum = n.match(/\d+/)[0];
        modelName = 'model' + modelNum;
        modelParam = (n.substring(0, n.indexOf('.'))).replace(modelName,'');

        model.model = modelName;
        model[modelParam] = [];
        models.push(model);

        //if (Object.keys(model).length === 3) {
        //    models.push(model);
        //    model = {};
        //}


        fs.createReadStream(__dirname+'/data/'+n).pipe(csv.parse()).pipe(csv.transform(function(row) {
            model[modelParam].push(row);

        })).on('readable', function(){
            while(this.read()){}
        }).on('end', function() {
            console.log('finished reading file ' + n);
            if (key === (files.length - 1)) {
                fs.writeFile('result.json', JSON.stringify(models), function (err) {
                    if (err) throw err;
                    console.log(models.length + ' model(s) parsed');
                    console.log('done');
                });
            }

        }).on('error', function(error) {
            console.log(error);
        });    
    });
});

Я знаю, что одна из моих проблем - это то, что я скоро подталкиваю модель к массиву, в результате получается окончательный массив формы ниже, где model1 перезаписывается model2

[ { model: 'model2', A: [], B: [] },
  { model: 'model2', A: [], B: [] },
  { model: 'model2', A: [], B: [] },
  { model: 'model2', A: [], B: [] } ]

Вот почему я пробовал этот код

if (Object.keys(model).length === 3) {
  models.push(model);
  model = {};
}

но, конечно, это не сработало, потому что fs.createReadStream является асинхронным, и я очищаю модель с помощью model = {}, прежде чем он сможет нормально работать.

Сейчас я нахожусь на сцене, где чувствую, что я собираюсь по кругу и делаю хуже. Однако я хотел создать нечто более общее, теперь я был бы рад заставить его работать для представленного здесь случая, а затем я могу посмотреть на его улучшение.

Любая помощь будет действительно оценена!


Обновление 1

Следующее предложение сакиба хана о перемещении var model = {} внутри цикла помогло мне приблизиться к моей цели, но это все еще не так. Ниже приведен текущий результат

[
    {
        "model": "model1",
        "A": [
            [
                "1"
            ],
            [
                "2"
            ],
            [
                "3"
            ],
            [
                "4"
            ]
        ]
    },
    {
        "model": "model1",
        "B": [
            [
                "1"
            ],
            [
                "2"
            ],
            [
                "3"
            ],
            [
                "4"
            ]
        ]
    },
    {
        "model": "model2",
        "A": [
            [
                "1"
            ],
            [
                "2"
            ],
            [
                "3"
            ],
            [
                "4"
            ]
        ]
    },
    {
        "model": "model2",
        "B": [
            [
                "1"
            ],
            [
                "2"
            ],
            [
                "3"
            ],
            [
                "4"
            ]
        ]
    }
]

Обновление 2

Также после предложения Denys Denysiuk результат ближе к тому, что я хочу, но все же просто короткий

[
    {
        "model": "model1",
        "A": [
            "1",
            "2",
            "3",
            "4"
        ]
    },
    {
        "model": "model1",
        "B": [
            "1",
            "2",
            "3",
            "4"
        ]
    },
    {
        "model": "model2",
        "A": [
            "1",
            "2",
            "3",
            "4"
        ]
    },
    {
        "model": "model2",
        "B": [
            "1",
            "2",
            "3",
            "4"
        ]
    }
]

Это сработает, если бы я мог как-то перебрать этот последний массив объектов, объединив объекты с соответствующим именем model. В настоящее время я просматриваю документы lodash, чтобы узнать, могу ли я что-то понять. Я отправлю сообщение здесь, если я это сделаю.

4b9b3361

Ответ 1

Попробуйте следующее:

fs.readdir(__dirname+'/data', function(err, files) {

    _.forEach(files, function(n, key) {

        console.log('Analysing file: ' + n);            

        var modelNum = n.match(/\d+/)[0];
        var modelName = 'model' + modelNum;
        var modelParam = (n.substring(0, n.indexOf('.'))).replace(modelName,'');

        var model = {};
        var isNewModel = true;
        for(var i = 0; i < models.length; i++) {
            if(models[i].model == modelName) {
               model = models[i];
               isNewModel = false;
               break;
            }
        }
        if(isNewModel) {
            model.model = modelName;
            models.push(model);
        }

        model[modelParam] = [];

        fs.createReadStream(__dirname+'/data/'+n).pipe(csv.parse()).pipe(csv.transform(function(row) {
            model[modelParam].push(row[0]);

        })).on('readable', function(){
            while(this.read()){}
        }).on('end', function() {
            console.log('finished reading file ' + n);
            if (key === (files.length - 1)) {
                fs.writeFile('result.json', JSON.stringify(models), function (err) {
                    if (err) throw err;
                    console.log(models.length + ' model(s) parsed');
                    console.log('done');
                });
            }

        }).on('error', function(error) {
            console.log(error);
        });    
    });

Ответ 2

В коде есть очень маленькая ошибка кодирования.

var model = {}; должен находиться внутри цикла forEach.

Попробуйте ввести код:

var csv = require('csv');
var fs = require('fs');
var parser = csv.parse();
var util = require('util');
var junk = require('junk');
var _ = require('lodash');
var models = [];


fs.readdir(__dirname+'/data', function(err, files) {

    _.forEach(files, function(n, key) {

        console.log('Analysing file: ' + n);
        var model = {};
        var modelName;
        var modelNum;
        var modelParam;


        modelNum = n.match(/\d+/)[0];
        modelName = 'model' + modelNum;
        modelParam = (n.substring(0, n.indexOf('.'))).replace(modelName,'');

        model.model = modelName;
        model[modelParam] = [];
        models.push(model);

        //if (Object.keys(model).length === 3) {
        //    models.push(model);
        //    model = {};
        //}


        fs.createReadStream(__dirname+'/data/'+n).pipe(csv.parse()).pipe(csv.transform(function(row) {
            model[modelParam].push(row);

        })).on('readable', function(){
            while(this.read()){}
        }).on('end', function() {
            console.log('finished reading file ' + n);
            if (key === (files.length - 1)) {
                fs.writeFile('result.json', JSON.stringify(models), function (err) {
                    if (err) throw err;
                    console.log(models.length + ' model(s) parsed');
                    console.log('done');
                });
            }

        }).on('error', function(error) {
            console.log(error);
        });    
    });
});

Ответ 3

Node.js управляется событиями, поэтому, возможно, вы можете создать свой код с помощью модуля Event: https://nodejs.org/api/events.html

Ваша проблема кажется, что вы переопределяете предыдущие записи в своем массиве, поэтому, возможно, вам стоит перейти к следующему шагу (чтение другого CSV?) только тогда, когда предыдущий закончил писать все, что ему нужно.

Вы можете добавить эту логику в свой код с помощью Event.