【问题标题】:Transform JSON by grouping by date and thereafter by datetime in NodeJS通过在 NodeJS 中按日期分组,然后按日期时间分组来转换 JSON
【发布时间】:2020-10-20 13:17:13
【问题描述】:

我有如下的 IoT 读数 JSON:

[
    {
        "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
    }
]

我想通过仅按日期对数据进行分组来转换 JSON 架构,并在其中显示同一日期时间的所有读数(苯、O3、NO2)到一个对象中,如下所示:

[
  {
    "date": "2020-06-29",
    "values": [
      {
        "Benzene": 1.9,
        "t": "2020-06-29T23:59:59.000Z",
        "O3": 25.6
      }
    ]
  },
  {
    "date": "2020-06-30",
    "values": [
      {
        "Benzene": 0.6,
        "t": "2020-06-30T00:59:59.000Z",
        "NO2": 16.3
      },
      {
        "Benzene": 5.7,
        "t": "2020-06-30T01:59:59.000Z",
        "NO2": 12.6,
        "O3": 31.7
      },
      {
        "Benzene": 5.5,
        "t": "2020-06-30T02:59:59.000Z",
        "NO2": 11.7,
        "O3": 35.1
      },
      {
        "Benzene": 5.2,
        "t": "2020-06-30T03:59:59.000Z",
        "NO2": 35.5,
        "O3": 11.4
      },
      {
        "Benzene": 1,
        "t": "2020-06-30T04:59:59.000Z",
        "NO2": 44.6,
        "O3": 4.9
      },
      {
        "Benzene": 2.1,
        "t": "2020-06-30T05:59:59.000Z",
        "NO2": 19.9,
        "O3": 32.8
      },
      {
        "Benzene": 4.2,
        "t": "2020-06-30T06:59:59.000Z",
        "NO2": 11.2,
        "O3": 46.4
      },
      {
        "Benzene": 3.4,
        "t": "2020-06-30T07:59:59.000Z",
        "NO2": 8.2,
        "O3": 55.6
      }
    ]
  }
]

我使用了以下方法可能非常多余并且不是特别有效。 (json_from_csv_filtered 包含顶部报告的原始 JSON)

   const data = Object.values(json_from_csv_filtered.reduce((groups, {
        datetime,
        ...rest
    }) => {
        if (!groups[datetime]) {
            groups[datetime] = {}
        }
        key = Object.keys({
            ...rest
        })
        value = Object.values({
            ...rest
        })
        groups[datetime][key[0]] = value[0];
        groups[datetime]['t'] = datetime
        return groups;
    }, []));

    const result = data.reduce((groups, readings) => {
        const date = readings.t.split('T')[0];
        if (!groups[date]) {
            groups[date] = [];
        }
        groups[date].push(readings);
        return groups;
    }, {})

    const groupArrays = Object.keys(result).map((date) => {
        return {
            date,
            values: result[date]
        };
    });


    console.log(JSON.stringify(groupArrays, null, 2));

谁能提出更好的方法? 而且't'键,代表读数的日期时间,不知道为什么,总是出现在'Benzene'键之后,我想应该是相反的。

谢谢。

【问题讨论】:

  • 请查看您上一篇文章的answer

标签: javascript node.js arrays json grouping


【解决方案1】:

您可以为长日期和短日期取两个哈希表并获取短日期的值。

为了更深入地了解,您可以查看包含两个属性 longshortr 对象。

{
    long: {
        "2020-06-29T23:59:59.000Z": {              // id: 3
            t: "2020-06-29T23:59:59.000Z",
            Benzene: 1.9,
            O3: 25.6
        },
        "2020-06-30T00:59:59.000Z": {              // id: 4
            t: "2020-06-30T00:59:59.000Z",
            Benzene: 0.6,
            NO2: 16.3
        },
        "2020-06-30T01:59:59.000Z": {              // id: 5
            t: "2020-06-30T01:59:59.000Z",
            Benzene: 5.7,
            NO2: 12.6,
            O3: 31.7
        },
        // ...
    },
    short: {
        "2020-06-29": {
            date: "2020-06-29",
            values: [
                {                                  // ref: 3,
                    t: "2020-06-29T23:59:59.000Z",
                    Benzene: 1.9,
                    O3: 25.6
                }
            ]
        },
        "2020-06-30": {
            date: "2020-06-30",
            values: [
                {                                  // ref: 4,
                    t: "2020-06-30T00:59:59.000Z",
                    Benzene: 0.6,
                    NO2: 16.3
                },
                {                                  // ref: 5,
                    t: "2020-06-30T01:59:59.000Z",
                    Benzene: 5.7,
                    NO2: 12.6,
                    O3: 31.7
                }
            ]
        },
        // ...
    }
}

long 包含用于收集 lonmg 时间戳属性的对象,并将此对象推送到相应的 short 集合,该集合按一天中的日期分组。

short 属性中,所有对象最终都是结果集的一部分,具有分组的日期数据并按时间戳分组,long 日期。

var 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 }],
    result = Object.values(data
        .reduce((r, { datetime: t, ...o }) => {
            let date = t.slice(0, 10);
            if (!r.long[t]) {
                r.short[date] = r.short[date] || { date, values: [] };
                r.short[date].values.push(r.long[t] = { t });
            }
            Object.assign(r.long[t], o);
            return r;
        }, { long: {}, short: {} })
        .short
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

  • 感谢它运行良好。如果您可以添加一些 cmets,我还不是 100% 清楚...再次感谢。也许,我可以使用 'momentjs' 而不是 'slice' 来获得更大的灵活性,你同意吗?
  • @EanX, momentjs 不是必需的,因为通过使用符合 ISO 8601 的字符串,您可以只使用第一部分。请看一下编辑。
【解决方案2】:

我建议使用momentjs(https://momentjs.com/)。这是一个包含许多用于处理日期和时间的实用程序的库,我强烈推荐它!

这是一个例子:

const exampleData = [{
    "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
  },
  {
    "datetime": "2020-06-20T07:59:59.000Z",
    "O3": 14.6
  },
  {
    "datetime": "2020-06-20T07:59:59.000Z",
    "Benzene": 14.6
  }
]

const keyFormat = "YYYY-MM-DD"
const groupReadings = (readings) => {
  const groups = []
  readings.forEach(reading => {
    const dateMoment = moment(reading.datetime)
    const dateKey = dateMoment.format(keyFormat)

    let dateData = groups.find(x => x.date === dateKey)
    if (!dateData) {
      dateData = {
        date: dateKey,
        values: []
      }
      groups.push(dateData)
    }

    let groupedReading = dateData.values.find(x => x.t === reading.datetime)
    if (!groupedReading) {
      groupedReading = {
        t: reading.datetime
      }
      dateData.values.push(groupedReading)
    }

    const key = Object.keys(reading).filter(x => x !== 'datetime')[0]
    groupedReading[key] = reading[key]
  })
  
  return groups
}

const result = groupReadings(exampleData)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js"></script>

通过使用 MomentJs,您的代码将更具可读性和更易于维护。 希望对你有帮助,祝你好运!

编辑: 固定示例

【讨论】:

  • 谢谢,但它不起作用。我认为问题出在 const groups = {} 上,但我尝试了 const groups = [] 和 const groups = [{}] 都没有解决问题(find 不是函数)。
  • 你是对的,我应该将组初始化为一个空数组。我编辑了答案并添加了代码 sn-p
猜你喜欢
  • 2022-01-10
  • 2019-06-06
  • 1970-01-01
  • 2014-03-28
  • 2017-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-17
相关资源
最近更新 更多