Get all timestamps from json [duplicate] - javascript

This question already has answers here:
How can I access and process nested objects, arrays, or JSON?
(31 answers)
Closed 4 years ago.
I am working for the first time on a project with JSON but I need to get al timestamps form the JSON file to put it in a array in a chart that al the timestamps are displaying on the chart.
JSON file look like this:
[
{
timestamp: "1541404800",
data: {
OK: {
count: "8",
percentage: "100"
},
NOK: {
count: 0,
percentage: 0
}
}
},
{
timestamp: "1541408400",
data: {
OK: {
count: "1",
percentage: "100"
},
NOK: {
count: 0,
percentage: 0
}
}
}
]

what you are looking for is the function map. See documentation for more details.
for example:
var data = [
{
timestamp: '1541404800',
data: {
OK: {
count: '8',
percentage: '100'
},
NOK: {
count: 0,
percentage: 0
}
}
},
{
timestamp: '1541408400',
data: {
OK: {
count: '1',
percentage: '100'
},
NOK: {
count: 0,
percentage: 0
}
}
}
];
var timestamps = data.map(function(d) { return d.timestamp }));

Just use for to iterate over the array to get the data
var json = [
{
timestamp: '1541404800',
data: {
OK: {
count: '8',
percentage: '100'
},
NOK: {
count: 0,
percentage: 0
}
}
},
{
timestamp: '1541408400',
data: {
OK: {
count: '1',
percentage: '100'
},
NOK: {
count: 0,
percentage: 0
}
}
}
];
var newArr = [];
for (var i = 0; i < json.length; i++) {
newArr.push(json[i].timestamp);
}
console.log(newArr); // ['1541404800','1541408400']

Related

Javascript grouping

How can I add data by grouping with country label and create data array that has 12 index indicating months and containing value of data before grouping.
I need help, how to push and group the data according to the month number. e.x
arr = [
{ label: 'US', data: '10', monthNumber: 1 },
{ label: 'US', data: '2', monthNumber: 3 },
{ label: 'US', data: '60', monthNumber: 2 },
{ label: 'UK', data: '10', monthNumber: 5 },
{ label: 'SA', data: '1', monthNumber: 1 },
{ label: 'CA', data: '70', monthNumber: 1 },
{ label: 'SA', data: '10', monthNumber: 12 },
];
now i need the results to be like
[
{ label: 'US', data: [10,60,2,0,0,0,0,0,0,0,0,0] },
{ label: 'UK', data: [0,0,0,0,10,0,0,0,0,0,0,0] },
{ label: 'SA', data: [1,0,0,0,0,0,0,0,0,0,0,10] },
{ label: 'CA', data: [70,0,0,0,0,0,0,0,0,0,0,0] },
];
Create a new object by reducing over the array using the labels as object keys, and initialising the property value as an object with a label, and a pre-filled array of zeros. Then update the array with the data at the relevant position.
const arr=[{label:"US",data:"10",monthNumber:1},{label:"US",data:"2",monthNumber:3},{label:"US",data:"60",monthNumber:2},{label:"UK",data:"10",monthNumber:5},{label:"SA",data:"1",monthNumber:1},{label:"CA",data:"70",monthNumber:1},{label:"SA",data:"10",monthNumber:12}];
function grouper(arr) {
// `reduce` over the array passing in an
// empty object as the initial accumulator value
const out = arr.reduce((acc, c) => {
// Destructure the properties from the current
// iterated object
const { label, data, monthNumber } = c;
// If the label doesn't exist as a key on the object
// create it, and assign an object as its value, using
// the label, and adding a pre-filled array of zeros to
// its data property
acc[label] ??= { label, data: new Array(12).fill(0) };
// Update the data array with the data value at the
// appropriate position
acc[label].data[monthNumber - 1] = Number(data);
// Return the accumulator for the next iteration
return acc;
}, {});
// Finally get the array of updated objects
// from the accumulated data
return Object.values(out);
}
console.log(grouper(arr));
Additional documentation
Logical nullish assignment
fill
Object.values
For grouping, you could make use of reduce
const arr = [
{ label: "US", data: "10", monthNumber: 1 },
{ label: "US", data: "2", monthNumber: 3 },
{ label: "US", data: "60", monthNumber: 2 },
{ label: "UK", data: "10", monthNumber: 5 },
{ label: "SA", data: "1", monthNumber: 1 },
{ label: "CA", data: "70", monthNumber: 1 },
{ label: "SA", data: "10", monthNumber: 12 },
]
let res = arr.reduce((acc, { label, monthNumber, data }) => {
if (!acc[label]) acc[label] = Array(12).fill(0)
acc[label][monthNumber - 1] = Number(data)
return acc
}, {})
res = Object.entries(res).map(([label, data]) => ({ label, data }))
console.log(res)
First I have extracted the label from the current array.
After that, I have a loop through those labels, and inside that loop through the array, and created an object with store values of data and label.
please see the comments for a better understanding.
Important thing to notice here is that for the same month number for labels value will be replaced with the last one.
arr = [{
label: 'US',
data: '10',
monthNumber: 1
},
{
label: 'US',
data: '2',
monthNumber: 3
},
{
label: 'US',
data: '60',
monthNumber: 2
},
{
label: 'UK',
data: '10',
monthNumber: 5
},
{
label: 'SA',
data: '1',
monthNumber: 1
},
{
label: 'CA',
data: '70',
monthNumber: 1
},
{
label: 'SA',
data: '10',
monthNumber: 12
},
];
const labels = [];
const result = [];
// extracting unique labels
arr.forEach(item => {
!labels.includes(item.label) && labels.push(item.label);
})
// looping through labels
labels.forEach(label => {
// creating empty object
const object = {};
// creating data array with 12 values by default 0
const data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
// loop though array values
arr.forEach(item => {
// checking if current outer label is matching with array label
if (item.label == label) {
// if abive condition true add label key in object with value of current outer label
object["label"] = label;
// updating month value
data[item.monthNumber - 1] = item.data;
}
// adding data in object with key data.
object["data"] = data;
})
// pushing final object in result
result.push(object);
})
//printing final result
console.log(result);
Good starting point will be to group the data by label first.
Then take the values from that to remap the data.
Create a Month array generating a new array with 0 values
Loop through and add the data to the month array based on MonthNumber
const remap = () => {
let arr = [
{ label: 'US', data: '10', monthNumber: 1 },
{ label: 'US', data: '2', monthNumber: 3 },
{ label: 'US', data: '60', monthNumber: 2 },
{ label: 'UK', data: '10', monthNumber: 5 },
{ label: 'SA', data: '1', monthNumber: 1 },
{ label: 'CA', data: '70', monthNumber: 1 },
{ label: 'SA', data: '10', monthNumber: 12 }
];
return Object.values(
arr.reduce((acc, v) => {
if (!acc.hasOwnProperty(v.label)) {
acc[v.label] = [];
}
acc[v.label].push(v);
return acc;
}, {})
).map((flatData) => {
const label = Array.isArray(flatData) && flatData.length > 0 ? flatData[0].label : '';
const monthArray = new Array(12).fill(0);
flatData.forEach(({ data, monthNumber }) => {
monthArray[monthNumber] = parseInt(data);
});
return { label, data: monthArray };
});
};
console.log(remap())
Try this solution:
function setupGraph(arr){
data = [];
for (let i = 0; i < arr.length; i++) {
let found = false;
for (let j = 0; j < data.length; j++) {
if (data[j].label === arr[i].label) {
data[j].data[arr[i].monthNumber - 1] = Number(arr[i].data);
found = true;
break;
}
}
if (!found) {
data.push({ label: arr[i].label, data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] });
data[data.length - 1].data[arr[i].monthNumber - 1] = Number(arr[i].data);
}
}
return data;
}
Testing the function:
arr = [
{ label: 'US', data: '10', monthNumber: 1 },
{ label: 'US', data: '2', monthNumber: 3 },
{ label: 'US', data: '60', monthNumber: 2 },
{ label: 'UK', data: '10', monthNumber: 5 },
{ label: 'SA', data: '1', monthNumber: 1 },
{ label: 'CA', data: '70', monthNumber: 1 },
{ label: 'SA', data: '10', monthNumber: 12 },
];
let result = setupGraph(arr)
console.log(result);
[
{
label: 'US',
data: [
10, 60, 2, 0, 0,
0, 0, 0, 0, 0,
0, 0
]
},
{
label: 'UK',
data: [
0, 0, 0, 0, 10,
0, 0, 0, 0, 0,
0, 0
]
},
{
label: 'SA',
data: [
1, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 10
]
},
{
label: 'CA',
data: [
70, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0
]
}
]
const defaultMonthsData = [0,0,0,0,0,0,0,0,0,0,0,0];
const arr = [
{ label: 'US', data: '10', monthNumber: 1 },
{ label: 'US', data: '2', monthNumber: 3 },
{ label: 'US', data: '60', monthNumber: 2 },
{ label: 'UK', data: '10', monthNumber: 5 },
{ label: 'SA', data: '1', monthNumber: 1 },
{ label: 'CA', data: '70', monthNumber: 1 },
{ label: 'SA', data: '10', monthNumber: 12 },
];
const results = _(arr)
.groupBy("label")
.map((value, label) => {
const monthsData = JSON.parse(JSON.stringify(defaultMonthsData));
return {
label,
data: _.map(value, function(o, index) {
monthsData[o.monthNumber] = parseInt(o.data);
return monthsData
})[0],
}
}).value();
console.log(results)
You can try with this (I'm using lodash 4.13.1). Thanks

How to spread inner object

I have data like this
finalValue [
{ _id: { _id: 'OUTCOME_APPROUVED' }, count: 1 },
{ _id: { _id: 'OUTCOME_SWITCH_INTERFACE' }, count: 5 }
]
I want to spread the inner object and change the keys to name and value to make final value looks like this
finalValue [
{ name: 'OUTCOME_APPROUVED' , value: 1 },
{ name: 'OUTCOME_SWITCH_INTERFACE' , value: 5 }
]
try this :
var finalValue = [
{ _id: { _id: 'OUTCOME_APPROUVED' }, count: 1 },
{ _id: { _id: 'OUTCOME_SWITCH_INTERFACE' }, count: 5 }
]
var newValue = finalValue.map(({_id:{_id},count}) => {
return {name:_id , value:count}
})
console.log(newValue)
[JS]
You could use map instead of spreading, and not sure about how you could spread it to format it the way you want.
const inputValue = [ { _id: { _id: 'OUTCOME_APPROUVED' }, count: 1 },
{ _id: { _id: 'OUTCOME_SWITCH_INTERFACE' }, count: 5 }]
const computedValue = inputValue.map((data) => {
return { name: data._id._id, value: data.count };
});

Flatten Nested Objects and Output Array

I have a deeply nested object that has the following schema:
const data = {
Car1: {
key: "Car",
value: "1",
child: {
Driver1: {
key: "Driver",
value: "1",
child: {
Trip1: {
key: "Trip",
value: 1,
metrics: { distance: 1, time: 2 }
}
}
},
Driver2: {
key: "Driver",
value: "2",
child: {
Trip1: {
key: "Trip",
value: 1,
metrics: { distance: 3, time: 4 }
},
Trip2: {
key: "Trip",
value: 2,
metrics: { distance: 5, time: 6 }
}
}
}
}
}
}
That I need to flatten into a singular array of objects, with each object in the array having all the properties of its direct child(ren).
Each nested object child is a Record of objects that have properties key and value.
The last object in the nested structure always has a property called metrics that should be flattened into the object as well.
So the output would look something like:
[
{ Car: 1, Driver: 1, Trip: 1, distance: 1, time: 2 },
{ Car: 1, Driver: 2, Trip: 1, distance: 3, time: 4 },
{ Car: 1, Driver: 2, Trip: 2, distance: 5, time: 6 }
]
I have tried the following code but it only captures one level of depth in the child tree:
private flattenOutput(child: Record<string, OutputChild> = this.output): any[] {
console.log('flattening', Object.keys(child));
return Object.values(child).map((child) => {
return Object.assign(
{},
{ [child.key]: child.value },
...this.flattenOutput(child.child),
child.metrics || {},
);
}, {});
}
By having correct nested objects, you could take a recursive approach and collect key/value and return a flat array with wanted objects.
const
collect = (object, temp = {}) => Object
.values(object)
.flatMap(({ key, value, child, metrics }) => child
? collect(child, { ...temp, [key]: value })
: { ...temp, [key]: value , ...metrics }
),
data = { Car1: { key: "Car", value: "1", child: { Driver1: { key: "Driver", value: "1", child: { Trip1: { key: "Trip", value: 1, metrics: { distance: 1, time: 2 } } } }, Driver2: { key: "Driver", value: "2", child: { Trip1: { key: "Trip", value: 1, metrics: { distance: 3, time: 4 } }, Trip2: { key: "Trip", value: 2, metrics: { distance: 5, time: 6 } } } } } } },
result = collect(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I will do that this way :
data =
{ Car1: { key: "Car", value: "1", child:
{ Driver1: { key: "Driver", value: "1", child:
{ Trip1: { key: "Trip", value: 1, metrics: { distance: 1, time: 2} }
} }
, Driver2:
{ key: "Driver", value: "2", child:
{ Trip1: { key: "Trip", value: 1, metrics: { distance: 3, time: 4} }
, Trip2: { key: "Trip", value: 2, metrics: { distance: 5, time: 6} }
} } } } }
let result = []
for (let Car in data )
for (let Driver in data[Car].child)
for (let Trip in data[Car].child[Driver].child)
result.push(
{ Car : data[Car].value
, Driver : data[Car].child[Driver].value
, Trip : data[Car].child[Driver].child[Trip].value
, distance : data[Car].child[Driver].child[Trip].metrics.distance
, time : data[Car].child[Driver].child[Trip].metrics.time
})
console.log( result )
.as-console-wrapper { max-height: 100% !important; top: 0; }

Cant implement correct sorting in javaScript using Array.sort

I have an array of profiles and each array contain profile object that contain "rating" object that contains 2 values:
Field named "totalRates" - that hold the value of total sum of rates per profile
Array named "rates" - array of objects that contains users id and the value each user rated for this spesific profile.
I want to get the top 3 rated user.
For that i have to map over all profiles and for each profile take the total rate of profile divide by rates.length to get the average and sort.
So what i did is:
router.get('/rating/top',async (req,res)=>{
try{
const profiles=await Profile.find().populate('user',['name','avatar'])
const ratedProfiles = profiles.map(( profile) =>{
if(profile.rating.rates.length>0)
return profile
})
//'BEFORE SORT'
const topRated = ratedProfiles.sort((a, b) => (a.rating.totalRates/a.rating.rates.length) - (b.rating.totalRates/b.rating.rates.length));
//AFTER SORT'
}
catch(err){
console.error(err.message);
res.status(500).send('Server error');
}
})
the first cell from my output in ratedProfiles:
{
[0] rating: { totalRates: 5, rates: [Array] },
[0] skills: [ 'css' ],
[0] _id: 5f3c3be9ebadb42a189640d5,
[0] user: {
[0] _id: 5f3c3bd1ebadb42a189640d4,
[0] name: 'Yosef Zaltsman',
[0] avatar: 'http://localhost:5000/public/5f3c3bd1ebadb42a189640d4.jpeg'
[0] },
[0] gender: '0',
[0] status: 'Junior Developer',
[0] experience: [],
[0] education: [],
[0] __v: 1
[0] },
I got same results before and after sorting.
What did i do wrong?
You need to sum up all the values of each rating and then divide this sum by the total number of ratings (i.e. calculating the average rating). Then you can sort by this average and take the first three values of the resulting array.
Here's a very "verbose" way to do this in order to to show you what's going on:
const ratedProfiles = [
{ rating: { totalRates: 5, rates: [{ value: 10 }, { value: 30 }, { value: 10 }, { value: 10 }, { value: 20 }] } },
{ rating: { totalRates: 1, rates: [{ value: 20 }] } },
{ rating: { totalRates: 2, rates: [{ value: 20 }, { value: 40 }] } },
{ rating: { totalRates: 3, rates: [{ value: 5 }, { value: 3 }, { value: 2 }] } },
{ rating: { totalRates: 4, rates: [{ value: 1 }, { value: 3 }, { value: 2 }, { value: 8 }] } },
];
const mappedSumRatedProfiles = ratedProfiles.map(profile => {
const sum = profile.rating.rates.reduce((prev, rate) => rate.value + prev, 0);
return { rating: { ...profile.rating }, avg: sum / profile.rating.totalRates };
});
mappedSumRatedProfiles.sort((a, b) => {
return b.avg - a.avg;
});
console.log(mappedSumRatedProfiles.slice(0,3));

Comparing Two Arrays and Grouping into Inserts and Updates

I am comparing two arrays and then grouping them into inserts and updates. The updates array should end up including elements that match on id == Id, but where open_balance !- DocumentAmount. The inserts array should include only elements where the id != Id. Notice I am running both through the toString() method because in my scenario one is of type String whereas the other is of type Integer from two different SQL Databases.
Now, with the code I have now, the first grouping works - via the findRecordsToUpdate() function, I get all of the elements matched correctly for the updates - which should be two elements, because these two match on id, but not on the amount:
recordsToUpdate: [
{ Id: '333', DocumentAmount: 20 },
{ Id: '444', DocumentAmount: 10 }
]
But the inserts, which is produced by the findRecordsToInsert() function, are not correct. According to my data I should end up with one element, with an Id of '555' in my recordsToUpdate array, because it's the only element with an Id not found in the other array -- i.e. it's a new record to insert. But instead I end up with 13 elements with my current code?
What am I missing here and what do I need to change to get the correct inserts populated to my recordsToInsert array?:
const sourceArr = [
{ id: 111, open_balance: 10 },
{ id: 222, open_balance: 20 },
{ id: 333, open_balance: 10 },
{ id: 444, open_balance: 20 },
]
const targetArr = [
{ Id: '111', DocumentAmount: 10 },
{ Id: '222', DocumentAmount: 20 },
{ Id: '333', DocumentAmount: 20 },
{ Id: '444', DocumentAmount: 10 },
{ Id: '555', DocumentAmount: 10 },
]
function findRecordsToUpdate () {
if (sourceArr.length && targetArr.length) {
let recordsToUpdate = [];
for (let t of targetArr) {
for (let s of sourceArr) {
if ((t.Id.toString() == s.id.toString()) && (t.DocumentAmount != s.open_balance)) {
recordsToUpdate.push(t);
}
}
}
console.log('recordsToUpdate: ', recordsToUpdate);
return recordsToUpdate;
}
};
function findRecordsToInsert () {
if (sourceArr.length && targetArr.length) {
let recordsToInsert = [];
for (let t of targetArr) {
for (let s of sourceArr) {
if (t.Id.toString() != s.id.toString()) {
recordsToInsert.push(t);
}
}
}
console.log('recordsToInsert: ', recordsToInsert);
return recordsToInsert;
}
};
findRecordsToUpdate();
findRecordsToInsert();
By the way, to clarify, my findRecordsToInsert() function should return a recordsToInsert array like this when done, as the record with an Id of 555 is the only record from the second array that doesn't exist in the first array:
recordsToInsert: [{ Id: '555', DocumentAmount: 10 }]
So, to be clear, it's just the findRecordsToInsert() function that is not working correctly at present.
Use a combination of Array#filter and Array#find to get your insert and update arrays out of targetArr.
'use strict';
const sourceArr = [
{ id: 111, open_balance: 10 },
{ id: 222, open_balance: 20 },
{ id: 333, open_balance: 10 },
{ id: 444, open_balance: 20 },
];
const targetArr = [
{ Id: '111', DocumentAmount: 10 },
{ Id: '222', DocumentAmount: 20 },
{ Id: '333', DocumentAmount: 20 },
{ Id: '444', DocumentAmount: 10 },
{ Id: '555', DocumentAmount: 10 },
];
// Target records with a matching source (on ID) where the amount has changed.
// Update these.
const recordsToUpdate = targetArr
.filter(tar => sourceArr
.find(source => source.id === Number(tar.Id) && source.open_balance !== tar.DocumentAmount));
console.log(recordsToUpdate);
// Target records that have no matching source record (i.e. new records).
// Insert these.
const recordsToInsert = targetArr
.filter(tar => !sourceArr
.find(source => source.id === Number(tar.Id)));
console.log(recordsToInsert);
Edit
Just for the record, in your original code the search in findRecordsToInsert is incorrect. To fix the issue, try to find each target in source and, if not found, add target to the insert array. But it's just a long-winded version of filter-find.
const sourceArr = [
{ id: 111, open_balance: 10 },
{ id: 222, open_balance: 20 },
{ id: 333, open_balance: 10 },
{ id: 444, open_balance: 20 },
]
const targetArr = [
{ Id: '111', DocumentAmount: 10 },
{ Id: '222', DocumentAmount: 20 },
{ Id: '333', DocumentAmount: 20 },
{ Id: '444', DocumentAmount: 10 },
{ Id: '555', DocumentAmount: 10 },
]
function findRecordsToInsert () {
if (sourceArr.length && targetArr.length) {
const recordsToInsert = [];
for (const t of targetArr) {
let found = false;
for (let i = 0; i < sourceArr.length && !found; ++i) {
if (t.Id.toString() === sourceArr[i].id.toString())
found = true;
}
if (!found)
recordsToInsert.push(t);
}
console.log('recordsToInsert: ', recordsToInsert);
return recordsToInsert;
}
};
findRecordsToInsert();
You could take a hash table and just filter the target array.
const
sourceArr = [{ id: 111, open_balance: 10 }, { id: 222, open_balance: 20 }, { id: 333, open_balance: 10 }, { id: 444, open_balance: 20 }],
targetArr = [{ Id: '111', DocumentAmount: 10 }, { Id: '222', DocumentAmount: 20 }, { Id: '333', DocumentAmount: 20 }, { Id: '444', DocumentAmount: 10 }, { Id: '555', DocumentAmount: 10 }],
source = sourceArr.reduce((r, { id, open_balance }) => (r[id] = open_balance, r), {}),
recordsToUpdate = targetArr.filter(({ Id, DocumentAmount }) =>
Id in source && source[Id] !== DocumentAmount),
recordsToInsert = targetArr.filter(({ Id }) => !(Id in source));
console.log(recordsToUpdate);
console.log(recordsToInsert);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources