问题
I have a JSON of IoT readings as follow:
[
{
"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
}
]
I want to transform the JSON schema by grouping data by date only and inside it shows, into a single object, all readings (Benzene, O3, NO2) for the same datetime as follow:
[
{
"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
}
]
}
]
I used the following approach probably quite redundant and not particularly efficient. (json_from_csv_filtered contains the original JSON reported at the top)
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));
Could anyone suggest a better approach? Moreover, 't' key, representing readings' datetime, I don't know why, appear always after 'Benzene' key, I would like it should be the opposite.
Thanks.
回答1:
You could take two hash table for long and short date and get the short date's values.
For getting a deeper understanding, you could have a look to the r
object which contains two properties long
and short
.
{
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
contains objects for collecting the properties for a lonmg timestamp and pushes this object to the corresponding short
collection which is grouped by the short date of a day.
In the short
property, all objects are finaly part of the result set, with grouped day data and grouped by timestamp, the long date.
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; }
回答2:
I would suggest using momentjs
(https://momentjs.com/). It's a library that contains many utils for dealing with dates and times, I strongly recommend it!
Here is an example:
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>
By using MomentJs your code will be much more readable and more easily maintained. I hope that helps, good luck!
Edit: Fixed example
来源:https://stackoverflow.com/questions/62654005/transform-json-by-grouping-by-date-and-thereafter-by-datetime-in-nodejs