Modifying the values inside an object - javascript

I am trying to alter object returned from an api to have a similar structure to another data set in my app and push them into an Array. So that I can add this data to my original data. But I am getting a strange result from my reduce function.
The data is coming in like this:
{
count: 4,
datapoints: [
{
Date: "2021-05-22",
score: 0,
},
{
Date: "2021-05-23",
score: 0,
},
{
Date: "2021-05-24",
score: 0,
},
{
Date: "2021-05-25",
score: 114,
},
],
};
I have a reduce function that looks like this:
const riskScores = await api.PCC.riskAssessment(userID, startdate, endDate);
const riskScoresFormatted = riskScores.datapoints.reduce((result, data) => {
const scores = result["riskAssessment"] || [];
scores.push({
value: data.score,
unit: "none",
recordedDate: data.Date,
method: "none",
});
result["riskAssessment"] = scores;
return result;
});
When I console out riskScoresFormatted Im getting something that looks like what I want but its coming out with the newly formatted objects nested inside the first object iterated over. like this:
{ Date: "2021-05-22"
riskAssessment: [{value: 0, unit: "none", recorded...}{...}] <- the data I need
score: 0
}
So I see clearly Im doing something wrong. I want to have all the newly formatted objects pushed inside an array with the key of "riskAssessment". Can anyone spot what Im doing wrong?

Provide the empty array [] as the initial data for the array at the end of reduce function.
const riskScoresFormatted = riskScores.datapoints.reduce((result, data) => {
const scores = result["riskAssessment"] || [];
scores.push({
value: data.score,
unit: "none",
recordedDate: data.Date,
method: "none",
});
result["riskAssessment"] = scores;
return result;
},[]);
Output
[
{
"value": 0,
"unit": "none",
"recordedDate": "2021-05-22",
"method": "none"
},
{
"value": 0,
"unit": "none",
"recordedDate": "2021-05-23",
"method": "none"
},
{
"value": 0,
"unit": "none",
"recordedDate": "2021-05-24",
"method": "none"
},
{
"value": 114,
"unit": "none",
"recordedDate": "2021-05-25",
"method": "none"
}
]

From what I gather, you want riskAssessment to be a new array with your new objects.
You're setting scores to be the previous value of riskAssessment. It will inherit the previous state, and you're just adding to it. Try to initialize it as an empty array directly, and then push your values to it.
const riskScoresFormatted = riskScores.datapoints.reduce((result, data) => {
const scores = [];
scores.push({
value: data.score,
unit: "none",
recordedDate: data.Date,
method: "none",
});
result["riskAssessment"] = scores;
return result;
});

Related

How to check whether a JSON key's value is an array or not if you don't know the key

How do I check whether a value in an JSON key's value is an array if you don't know the key's name?
I may receive 2 different formats of a JSON object:
{
"person": [{
"id": "1",
"x": "abc",
"attributes": ["something"]
},
{
"id": "1",
"x": "abc"
}
]
}
Depending on the format I will parse it differently. My goal is to create an if statement that would detect whether the value of the key is an Array or just a value, without knowing the name of the key (in above code let's assume I don't really know the name of "attributes"). How do I achieve that? Not only do I have to loop through all person objects, but also all of it's keys.
I found a solution that does that knowing the name of the attribute and there's just one object "person", but don't know how to build on that with multiple "person" objects and not knowing the name of the key?
if (Array.isArray(json.person['attributes'])) // assuming I hold the JSON in json var and I parse it with JSON.parse
{
}
You can try something like this:
Data payload:
const payload = {
person: [
{
id: 1,
x: 'abc',
attributes: ['something']
},
{
id: 1,
x: 'abc'
}
]
};
Function that will return if some entry has an Array as value:
const arrayEntries = json => {
let response = [{
isArray: false,
jsonKey: null,
jsonValue: null
}];
Object.entries(json).map(entry => {
if (Array.isArray(entry[1])) {
response.push({
isArray: true,
jsonKey: entry[0],
jsonValue: entry[1]
});
}
});
return response;
}
Usage example:
payload.person.map(person => {
console.log(arrayEntries(person));
});
Return will be something like this:
Codepen link: https://codepen.io/WIS-Graphics/pen/ExjVPEz
ES5 Version:
function arrayEntries(json) {
var response = [{
isArray: false,
jsonKey: null,
jsonValue: null
}];
Object.entries(json).map(function(entry) {
if (Array.isArray(entry[1])) {
response.push({
isArray: true,
jsonKey: entry[0],
jsonValue: entry[1]
});
}
});
return response;
}
payload.person.map(function(person) {
console.log(arrayEntries(person));
});

How to remove a common property from each array which is nested

I have an array like below: I want to remove origin: 0 property and add it value directly using Javascript es6 feature. How to remove same repeated property from a nested array.
const orginalData = {
name: {
origin: 0,
value: 'christi'
},
location: {
origin: 0,
value: 'Blr'
},
address: {
origin: 0,
value: [{
"streetAddress1": {
"origin": 0,
"value": '12th street'
},
"city1": {
"origin": 0,
"value": 'Maxwell'
}
},
{
"streetAddress2": {
"origin": 0,
"value": '10=]]]]]]]th street'
},
"city2": {
"origin": 0,
"value": 'Coxwell'
}
}
]
}
}
const finalData = {
name: 'christi',
location: 'Blr',
address: [{
streetAddress1: '10th street',
city1: 'Maxwell'
},
{
streetAddress2: '12th street',
city2: 'Coxwell'
}
]
}
You could create generic function like this. reduce the entries of an object to remove a level of nesting and update with nested value. If value as an array, recursively call the function on each object using map and get an array of restructured objects. This will work for any level of nesting
const orginalData={name:{origin:0,value:"christi"},location:{origin:0,value:"Blr"},address:{origin:0,value:[{streetAddress1:{origin:0,value:"12th street"},city1:{origin:0,value:"Maxwell"}},{streetAddress2:{origin:0,value:"10=]]]]]]]th street"},city2:{origin:0,value:"Coxwell"}}]}};
function restructure(obj) {
return Object.entries(obj).reduce((acc, [k, { value }]) => {
acc[k] = Array.isArray(value) ? value.map(restructure) : value;
return acc;
}, {})
}
const finalData = restructure(orginalData)
console.log(finalData)
If you're using NodeJs you could use omit-deep to remove any property you want, regardless of where it is within the object.
For example, this:
const omitDeep = require('omit-deep');
const data = {
name: { origin: 0, value: 'christi' },
location: { origin: 0, value: 'Blr' },
address: {
origin: 0,
value: [
{ streetAddress1: { origin: 0, value: '12th street' }, city1: { origin: 0, value: 'Maxwell' } },
{ streetAddress2: { origin: 0, value: '10=]]]]]]]th street' }, city2: { origin: 0, value: 'Coxwell' } }
]
}
};
const finalData = omitDeep(data, 'origin');
Produces this result:
{
name: { value: 'christi' },
location: { value: 'Blr' },
address: {
value: [
{ streetAddress1: { value: '12th street' }, city1: { value: 'Maxwell' } },
{ streetAddress2: { value: '10=]]]]]]]th street' }, city2: { value: 'Coxwell' } }
]
}
};
first if you want to edit your data, it can't be a const, so change const by let or var.
second
you can use for loop to do that, you can juste write a function or add a function to JSON object
// first logique as global function
function keepKey(data, keep) {
for(let key in data) data[key] = data[key][keep];
}
// second logique as global function
function removeKey(data, remove, assignRest) {
for(let key in data){
//get the item
let item = data[key];
if(typeof item === 'object'){
//if you put 'use strict' at the top you have to use a loop
let temp = {}, lastKey = '';
for(let itemKey in item){
if(itemKey !== remove){
if(assignRest === true) temp = item[itemKey];
else temp[itemKey] = item[itemKey];
}
}
data[key] = temp;
//else you can use directly delete
//delete item[remove];
}
}
}
// add the function to JSON object
JSON.keepKey = {...function...}
// or
JSON.removeKey = {...function...}
JSON.keepKey(orginalData, 'value');
// will give you
{name: 'christi',location: 'Blr',...}
JSON.removeKey(orginalData, 'value', true);
// will give you
{name: 'christi',location: 'Blr',...}
JSON.removeKey(orginalData, 'value', false);
// will give you
{name: {value : 'christi'},location: {value: 'Blr'},...}
const finalData = {
// ...originalData, uncommnent this if you have more originalData has props that you do not want to chnage.
name: originalData.name.value,
location: originalData.location.value,
address: originalData.address.value.map(item => {
const { origin, ...rest } = item;
return rest;
}),
};
This is just a copy of adiga's logic, made more explicit with extraneous identifiers and comments.
It's intended to help with understanding of the reduce method (and other JavaScript features) and of recursion.
const originalData = {
name: { origin: 0, value: 'christi' },
location: { origin: 0, value: 'Blr' },
address: {
origin: 0,
value: [
{
"streetAddress1": { "origin": 0, "value": '12th street' },
"city1": { "origin": 0, "value": 'Maxwell' }
},
{
"streetAddress2": { "origin": 0, "value": '10=]]]]]]]th street' },
"city2": { "origin": 0, "value": 'Coxwell' }
}
]
}
};
function restructure(obj) {
// Whether `restructure` is called directly or recursively, it builds and returns
// a new object.
return Object.entries(obj).reduce( (acc, curr, ind, arr ) => {
// Here, `entries` is a 2D array where each 'row' is a property and the two
// 'columns' are the property name and property value.
// We identify them explicitly below and assume that that the property value
// is an object with a subproperty called "value", which we also identify.
const propKey = curr[0], propVal = curr[1], subpropVal = propVal["value"];
// Logs the index (ie 'row' number) of the current property and its property name
//console.log(ind, propKey);
// Here, `acc` is the object we will return. We give `acc` a new property with
// the same name as the current property.
// If the "value" subproperty of the current property holds an array, the new
// property will hold an array of objects, each of which is a `restructure`d
// version of an object from the source array. (This can happen many times,
// restructuring nested objects from many nested arrays.)
// If not, the new property will have the same value as the "value" subproperty does
acc[propKey] = Array.isArray(subpropVal) ? subpropVal.map(restructure) : subpropVal;
// If this call to `restructure` was recursive, we will continue looping through
// the array we are currently processing.
// If this was the original call, we're done and log our `finalData` to the console.
return acc;
}, {})
}
const finalData = restructure(originalData);
console.log(finalData);

How to Convert an Array of Objects into an Object of Associative Arrays in Javascript

I am receiving the following structure from a system. I am attempting to bend it into the form needed for a particular graph utilizing chartjs. Given the JSON data structure … an array of objects in an object:
{
"chart": [
{
"date": "2018-10-29",
"done": 3,
"todo": 10
},
{
"date": "2018-10-30",
"done": 4,
"todo": 7
},
{
"date": "2018-10-31",
"done": 5,
"todo": 12
}
]
}
I need the desired JSON data structure ... an object of arrays (in one array, in one object)
{
"chart": [{
"date": [
"2018-10-29",
"2018-10-29",
"2018-10-31"
],
"done": [
3,
4,
5
],
"todo": [
10,
7,
12
]
}]
}
I have attempted to use the .map function but I don't seem to have the correct map-fu.
You could take an object and get all keys with ther values in single array.
var data = { chart: [{ date: "2018-10-29", done: 3, todo: 10 }, { date: "2018-10-30", done: 4, todo: 7 }, { date: "2018-10-31", done: 5, todo: 12 }] },
result = { chart: data.chart.reduce((r, o) => {
Object.entries(o).forEach(([k, v]) => (r[k] = r[k] || []).push(v));
return r;
}, {})
};
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
What about using reduce ?
const output = input.reduce((acc, curr) => ({
date: acc.date.concat(curr.date),
done: acc.done.concat(curr.done),
todo: acc.todo.concat(curr.todo),
}), { date: [], done: [], todo: [] });
const chartData = {
chart: [output],
};
Reference for reduce is here : https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/reduce
Here's a very explicit solution. There may be some slicker Javascript solutions; certainly you can do multiple .map calls, but that makes it less efficient.
// Variables
var dates = [];
var doneValues = [];
var todoValues = [];
// Loop through the original data once, collect the data.
originalJSON.forEach(function(data) {
dates.push(data["date"]);
doneValues .push(data["done"]);
todoValues .push(data["todo"]);
});
// Put it all together.
return {"chart": [{"date": dates, "done": doneValues , "todo": todoValues}]};
Modify it to suit your needs.

Merge arrays of object into single array of object

I am looking for merge arrays of object into single array of object and append key of object to each key from inner object's key
I have object like
var myObj = {
"Details": [{
"car": "Audi",
"price": 40000,
"color": "blue"
},
{
"car": "BMW",
"price": 35000,
"color": "black"
}
],
"Accounts": [{
"Total": 2000
},
{
"Total": 3000
}
]
}
and Keys and objects length is not known, I want to merge it like
[
{
"Detailscar": "Audi",
"Detailsprice": 40000,
"Detailscolor": "blue",
"AccountsTotal": 2000
},
{
"Detailscar": "BMW",
"Detailsprice": 35000,
"Detailscolor": "black",
"AccountsTotal": 3000
}
]
I have tried with Ramda mergeAll but it is not working in my case as it only merge objects
here is what I tried
var mergedArray = []
R.mapObjIndexed((instance, instanceName) => {
mergedArray.push(R.map((innerObj) => {
var customObject = {};
R.forEach((key) => {
customObject[`${instanceName}${key}`] = innerObj[key]
}, Object.keys(innerObj))
return customObject;
}, instance))
}, myObj)
I am trying add to each modified object to the mergerArray array but it adding for each iteration and finally, it is creating 2 arrays
mergedArray is still creating two different arrays with the key of the object to be appended to the properties of the object but I want it to be merged in the single array of object.
I am missing something. What should I do to resolve this issue?
Suggest some help.
Use Array.prototype.map and index as second parameter passsed to its callback to get element from Account object
const data = {
"Details": [
{
"car": "Audi",
"price": 40000,
"color": "blue"
},
{
"car": "BMW",
"price": 35000,
"color": "black"
},
{
"car": "Porsche",
"price": 60000,
"color": "green"
}
],
"Accounts": [
{
"Total": 2000
},
{
"Total": 3000
},
{
"Total": 3000
}
]
};
const mergeCarData = ({ Details, Accounts} = {}) => {
return Details.length === Accounts.length ? Details.map(({ car, price, color}, idx) => ({
Detailscar: car,
Detailsprice: price,
Detailscolor: color,
AccountsTotal: Accounts[idx].Total
})) : [];
};
console.log(mergeCarData(data));
In plain Javascript, you could iterate the keys of the given object and iterate the arrays and build a new object out of the inner properties with a new key.
var object = { Details: [{ car: "Audi", price: 40000, color: "blue" }, { car: "BMW", price: 35000, color: "black" }], Accounts: [{ Total: 2000 }, { Total: 3000 }] },
result = Object.keys(object).reduce(function (returnValue, parentKey) {
object[parentKey].forEach(function (currentObj, i) {
returnValue[i] = returnValue[i] || {};
Object.keys(currentObj).forEach(function (childKey) {
returnValue[i][parentKey + childKey] = currentObj[childKey];
});
});
return returnValue;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Well, it's not pretty, but you could do something like this:
const convert = pipe(
mapObjIndexed((val, name) => pipe(
map(toPairs),
map(map(([prop, propVal]) => objOf(name + prop, propVal))),
map(mergeAll),
)(val)),
values,
apply(zipWith(merge))
)
You can see this in action on the Ramda REPL.
Here you go, another option. I pulled a renameBy function from ramda recipe list. You can combine all the stuff on to one line if you want.
// https://github.com/ramda/ramda/wiki/Cookbook#rename-keys-of-an-object
const renameBy = R.curry((fn, obj) => R.pipe(R.toPairs, R.map(R.adjust(fn, 0)), R.fromPairs)(obj));
let convertNames = R.mapObjIndexed((value, key)=> {
return R.map(renameBy(R.concat(key)), value)
})
let mergeUp = R.pipe(R.values, R.reduce(R.mergeDeepLeft,[]), R.values)
let convert = R.pipe(convertNames, mergeUp)
convert(myObj)

How to iterate JSON with multiple levels?

Welcome, I got a problem with JSON file. I would like to iterate through it and get every status into array, but I got stuck. I load this file and parse it. Then I tried to use forEach but it did not worked. Thanks for help!
[{
"offers": [{
"advertiser_api_id": 12,
"status": 1
}, {
"advertiser_api_id": 13,
"status": 0
}]
}]
I assume this will be in javascript. You can try the following:
for (x in json[0].offers) {
console.log(json[0].offers[x].status);
}
You have got an array Of Objects inside Array.
Firstly, you need to parse the data from JSON to object using JSON.parse(data); Then, access the object offers. using the parsedData[0].offers object and then iterate over the array to get the status.
var data = `[{
"offers": [{
"advertiser_api_id": 12,
"status": 1
}, {
"advertiser_api_id": 13,
"status": 0
}]
}]`;
var parsedData = JSON.parse(data);
var result = [];
parsedData[0].offers.forEach((currentValue) => result.push(currentValue["status"]));
console.log(result)
You can use map function:
var data = [{
"offers": [{
"advertiser_api_id": 12,
"status": 1
}, {
"advertiser_api_id": 13,
"status": 0
}]
}]
var stats = data[0].offers.map(function(item) {
return item.status;
})
console.log(stats);
This loops through the object and prints the data to console - you likely did not reach the correct array to loop through.
var data = [{
"offers": [{
"advertiser_api_id": 12,
"status": 1
}, {
"advertiser_api_id": 13,
"status": 0
}]
}];
data[0].offers.forEach(function(element) {
console.log(element.status);
});
This will work
statuses = []
JSON.parse(data)[0].offers.forEach(x => statuses.push(x.status))
A recursive approach
var item = [{
"offers": [{
"advertiser_api_id": 12,
"status": 1
}, {
"advertiser_api_id": 13,
"status": 0
}]
}];
var statusArray = [];
function getStatusForALlLevels(item){
if(item.offers instanceof Array){
for(var i=0;i<item.offers.length;i++){
getStatusForALlLevels(item.offers[i]);
}
}else{
statusArray.push(item.status);
}
}
getStatusForALlLevels(item[0]);
console.log(statusArray);
You could use an iterative and recursive approach for getting status from multiple nested objects.
var data = [{ offers: [{ advertiser_api_id: 12, status: 1 }, { advertiser_api_ii: 13, status: 0 }] }],
status = data.reduce(function iter(r, o) {
if ('status' in o) {
r.push(o.status);
}
Object.keys(o).forEach(function (k) {
if (Array.isArray(o[k])) {
r = o[k].reduce(iter, r);
}
});
return r;
}, []);
console.log(status);

Categories