【问题标题】:Reshape JSON using lodash and reduce使用 lodash 重塑 JSON 并减少
【发布时间】:2023-03-26 10:36:01
【问题描述】:

我想从从 URL 下载的已解析 CSV 文件中重塑 JSON。

我使用 'csvtojson' 模块来解析 CSV 并创建一个需要重塑的 JSON。

下面是我的完整代码:

const _ = require('lodash')
// to handle datetimes
const moment = require('moment')
// to convert csv to json
const csv = require('csvtojson')

// to save files to disk
const fs = require('fs')
const fsPromises = fs.promises;
const path = require('path')

// to load data stream from url
const axios = require('axios')

// to schedule downloading
const schedule = require('node-schedule');
//let t = moment('2020-01-30 02:59:59+01')
// console.log(t.format())
// console.log(t.toDate())

const urlBaseFile = 'http://cemec.arpacampania.it/meteoambientecampania/php/downloadFileDati.php?path=/var/www/html/meteoambientecampania/prodotti/aria/arpac_dati_centraline'

const path_fileJSON = path.resolve(__dirname, '../data.json')
const path_fileCSV = path.resolve(__dirname, '../data.csv')

const downloadCSV = async (date) => {

    const url = urlBaseFile + '_' +
        (!date ? moment().format('YYYYMMDD') : date) + '.csv'

    const writerCSV = fs.createWriteStream(path_fileCSV)

    try {
        let response = await axios.get(url, {
            responseType: 'stream'
        })
        await response.data.pipe(writerCSV)
        const json_from_csv = await response.data.pipe(csv())
        const json_from_csv_filtered = json_from_csv.filter(d => d.descrizione == 'Portici Parco Reggia').map(d => {
            return {
                // convert to Date object UTC format
                // moment(d.data_ora).format()
                datetime: moment(d.data_ora).toISOString(),
                [d.inquinante]: parseFloat(d.valore),
                // pollutant: d.inquinante,
                // value: parseFloat(d.valore), // convert to float
                //unit: d.um
            }
        })

        await fsPromises.writeFile(path_fileJSON, JSON.stringify(json_from_csv_filtered, null, 4))

        const res = json_from_csv_filtered.reduce((acc, val) => {
            const find = acc.find(el => el.date === val.datetime.substring(0, 10));
            const {
                datetime,
                ...obj
            } = val;

            if (find) {
                find.values[0] = {
                    ...find.values[0],
                    ...obj
                };
            } else {
                acc.push({
                    date: datetime.substring(0, 10),
                    values: [{
                        t: datetime,
                        ...obj
                    }]
                });
            }
            return acc;
        }, []);
        console.log(JSON.stringify(res, null, 4))



    } catch (err) {

        console.error(err)
    }



}

downloadCSV()

我得到:

[
    {
        "date": "2020-06-28",
        "values": [
            {
                "t": "2020-06-28T23:59:59.000Z",
                "Benzene": 0.5,
                "NO2": 44.7,
                "O3": 23.2
            }
        ]
    },
    {
        "date": "2020-06-29",
        "values": [
            {
                "t": "2020-06-29T00:59:59.000Z",
                "Benzene": 4.3,
                "NO2": 11.5,
                "O3": 67.8
            }
        ]
    }
]

整体 JSON 架构是正确的,但我应该获取日期为 2020-06-29 的其他项目,而仅返回 1 个项目。

怎么了?

谢谢。

【问题讨论】:

  • 浏览一下你的脚本,find.values[0] 只会从 values 数组中获取第一个元素。也许这就是问题所在?
  • 不,这不是问题所在。使用“find.values”不会改变结果。
  • 与您之前的 post 一样,您的预期结果是将每个组对象 values 组合成单个元素 values 数组。您是否希望 group 的所有对象值都在一个数组中(具有多个对象而不是单个对象)?如果是这样,那么您应该将obj 值推入find.values 数组而不是将obj 解构为find.values[0]。如果我错了,请用正确的输入数据和输出数据澄清您的问题。
  • @ParthoShuvo,预期的输出应该是: [{ "date": "2020-06-30", "values": [ { "t": "2020-06-30T00:59: 59.000Z", "苯": 5.5, "NO2": 11.7, "O3": 35.1 }, { "t": "2020-06-30T01:59:59.000Z", "苯": 5.2, "NO2" : 15.7, "O3": 55.7 } ] } ] 在同一日期内有多个对象,但每小时有一个对象收集所有传感器读数。相反,我只获得最后一小时的读数。
  • @ParthoShuvo,在这个新的post 中,我希望能够澄清这个问题。我能够找到解决方案,但我最不喜欢它。如果您能提出更好的方法...谢谢!

标签: javascript node.js json lodash


【解决方案1】:

post 和您的 cmets,我假设您的响应数据将如下所示,据我从您的 cmets 了解,您希望按日期对来自 datetime 的值进行分组,然后在其中包含多个对象一个组的values 数组根据不同的小时基础。我用lodashgroupBy函数试过了。对于解决方案,我采用了两个分组方法

  1. 按日期分组来自datetime
  2. 每个组日期的组值

let data = [
    {
        "datetime": "2020-06-29T23:59:59.000Z",
        "Benzene": 1.9
    },
    {
        "datetime": "2020-06-30T00:59:59.000Z",
        "Benzene": 0.6
    },
    {
        "datetime": "2020-06-30T01:59:59.000Z",
        "Benzene": 5.7
    },
    {
        "datetime": "2020-06-30T02:59:59.000Z",
        "Benzene": 5.5
    },
    {
        "datetime": "2020-06-30T03:59:59.000Z",
        "Benzene": 5.2
    },
    {
        "datetime": "2020-06-30T04:59:59.000Z",
        "Benzene": 1
    },
    {
        "datetime": "2020-06-30T05:59:59.000Z",
        "Benzene": 2.1
    },
    {
        "datetime": "2020-06-30T06:59:59.000Z",
        "Benzene": 4.2
    },
    {
        "datetime": "2020-06-30T07:59:59.000Z",
        "Benzene": 3.4
    },
    {
        "datetime": "2020-06-30T00:59:59.000Z",
        "NO2": 16.3
    },
    {
        "datetime": "2020-06-30T01:59:59.000Z",
        "NO2": 12.6
    },
    {
        "datetime": "2020-06-30T02:59:59.000Z",
        "NO2": 11.7
    },
    {
        "datetime": "2020-06-30T03:59:59.000Z",
        "NO2": 35.5
    },
    {
        "datetime": "2020-06-30T04:59:59.000Z",
        "NO2": 44.6
    },
    {
        "datetime": "2020-06-30T05:59:59.000Z",
        "NO2": 19.9
    },
    {
        "datetime": "2020-06-30T06:59:59.000Z",
        "NO2": 11.2
    },
    {
        "datetime": "2020-06-30T07:59:59.000Z",
        "NO2": 8.2
    },
    {
        "datetime": "2020-06-29T23:59:59.000Z",
        "O3": 25.6
    },
    {
        "datetime": "2020-06-30T01:59:59.000Z",
        "O3": 31.7
    },
    {
        "datetime": "2020-06-30T02:59:59.000Z",
        "O3": 35.1
    },
    {
        "datetime": "2020-06-30T03:59:59.000Z",
        "O3": 11.4
    },
    {
        "datetime": "2020-06-30T04:59:59.000Z",
        "O3": 4.9
    },
    {
        "datetime": "2020-06-30T05:59:59.000Z",
        "O3": 32.8
    },
    {
        "datetime": "2020-06-30T06:59:59.000Z",
        "O3": 46.4
    },
    {
        "datetime": "2020-06-30T07:59:59.000Z",
        "O3": 55.6
    }
];
const groupsByDate = _.groupBy(data, val => val.datetime.split('T')[0]);
const res = Object.entries(groupsByDate).map(([date, vals]) => {
  const groupsByTime = _.groupBy(vals, val => val.datetime.split('T')[1]);
  return {
    date,
    values: Object.values(groupsByTime).map(arr => Object.assign({}, ...arr))
  };
});

console.log(JSON.stringify(res, null, 2));
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>

我也尝试将我的解决方案纳入您当前的方法

const json_from_csv_filtered = [
    {
        "datetime": "2020-06-29T23:59:59.000Z",
        "Benzene": 1.9
    },
    {
        "datetime": "2020-06-30T00:59:59.000Z",
        "Benzene": 0.6
    },
    {
        "datetime": "2020-06-30T01:59:59.000Z",
        "Benzene": 5.7
    },
    {
        "datetime": "2020-06-30T02:59:59.000Z",
        "Benzene": 5.5
    },
    {
        "datetime": "2020-06-30T03:59:59.000Z",
        "Benzene": 5.2
    },
    {
        "datetime": "2020-06-30T04:59:59.000Z",
        "Benzene": 1
    },
    {
        "datetime": "2020-06-30T05:59:59.000Z",
        "Benzene": 2.1
    },
    {
        "datetime": "2020-06-30T06:59:59.000Z",
        "Benzene": 4.2
    },
    {
        "datetime": "2020-06-30T07:59:59.000Z",
        "Benzene": 3.4
    },
    {
        "datetime": "2020-06-30T00:59:59.000Z",
        "NO2": 16.3
    },
    {
        "datetime": "2020-06-30T01:59:59.000Z",
        "NO2": 12.6
    },
    {
        "datetime": "2020-06-30T02:59:59.000Z",
        "NO2": 11.7
    },
    {
        "datetime": "2020-06-30T03:59:59.000Z",
        "NO2": 35.5
    },
    {
        "datetime": "2020-06-30T04:59:59.000Z",
        "NO2": 44.6
    },
    {
        "datetime": "2020-06-30T05:59:59.000Z",
        "NO2": 19.9
    },
    {
        "datetime": "2020-06-30T06:59:59.000Z",
        "NO2": 11.2
    },
    {
        "datetime": "2020-06-30T07:59:59.000Z",
        "NO2": 8.2
    },
    {
        "datetime": "2020-06-29T23:59:59.000Z",
        "O3": 25.6
    },
    {
        "datetime": "2020-06-30T01:59:59.000Z",
        "O3": 31.7
    },
    {
        "datetime": "2020-06-30T02:59:59.000Z",
        "O3": 35.1
    },
    {
        "datetime": "2020-06-30T03:59:59.000Z",
        "O3": 11.4
    },
    {
        "datetime": "2020-06-30T04:59:59.000Z",
        "O3": 4.9
    },
    {
        "datetime": "2020-06-30T05:59:59.000Z",
        "O3": 32.8
    },
    {
        "datetime": "2020-06-30T06:59:59.000Z",
        "O3": 46.4
    },
    {
        "datetime": "2020-06-30T07:59:59.000Z",
        "O3": 55.6
    }
];
const groupBy = (xs, f) => {
  return xs.reduce((acc, val) => {
          const key = f(val);
          const values = [...(acc[key] || []), val];
          acc[key] = values;
          return acc;
      }, {});
}

const groupsByDate = groupBy(json_from_csv_filtered, v => v.datetime.split("T")[0]);
const res = Object.entries(groupsByDate).map(([date, values]) => {
  const groupsByTime = groupBy(values, v => v.datetime.split("T")[1]);
  return {
    date,
    values: Object.values(groupsByTime).map(v => Object.assign({}, ...v))
  };
});
console.log(JSON.stringify(res, null, 2));

检查方法,希望能按照我的理解解决您的问题。

【讨论】:

    猜你喜欢
    • 2021-05-21
    • 2020-01-21
    • 1970-01-01
    • 1970-01-01
    • 2019-06-15
    • 2021-07-13
    • 1970-01-01
    • 2017-03-18
    • 1970-01-01
    相关资源
    最近更新 更多