Is there a simple way to transform this JSON back and forth? - javascript

We are using Postman for our API testing. Some object we are getting back are very verbose and not easy to handle, so I want to create a helper method to make them a bit more concise. I know there are all kind of transformation libraries like node-json-transform, selecttransform, jsontransforms, etc., but unfortunately I can only use the Postman Sandbox libraries and vanilla JS.
I am looking for the simplest (least amount of loc and functions) way to transform this object:
var verbose = [
{
"Key": "Name",
"Value": "John Doe",
"Instance": 1
},
{
"Key": "Age",
"Value": "33",
"Instance": 1
},
{
"Key": "Child",
"Value": "Jane",
"Instance": 1
},
{
"Key": "Child",
"Value": "Rocky",
"Instance": 2
}];
into this:
var concise = {
"Name": "John Doe",
"Age": "33",
"Child": ["Jane", "Rocky"]
};
and back again into the verbose form.
I already tried the native way of foreach-ing over each object and adding properties/values to a new object, but it went ugly soon when I reached the multiple instance key/value pairs. I can imagine there is an easier way using map/reduce but I am unfamiliar with those methods.

Based on how I've understood your question, you want to create key-value pairs from your verbose array of objects. However, if there are key clashes, then the values should be converted into an array.
With that in mind, you will have to:
Use forEach to loop through your array of objects.
If key does not clash, we simply create a new key-value pair
If key clashes, then it gets a bit tricky:
If key clashes and this is the first occurrence, we convert the value in the key-value pair into an array
If key clashes and this is not the first occurrence, we know we are looking at an array
Now we definitely has an array, so we push our value into it
See proof-of-concept below:
var verbose = [{
"Key": "Name",
"Value": "John Doe",
"Instance": 1
},
{
"Key": "Age",
"Value": "33",
"Instance": 1
},
{
"Key": "Child",
"Value": "Jane",
"Instance": 1
},
{
"Key": "Child",
"Value": "Rocky",
"Instance": 2
}];
var concise = {};
verbose.forEach(function(i) {
var key = i['Key'];
var value = i['Value'];
// If item exists, we want to convert the value into an array of values
if (key in concise) {
var item = concise[key];
// If it is not an array already, we convert it to an array
if (!Array.isArray(item))
item = [item];
item.push(value);
concise[key] = item;
}
// If item does not exist, we simply create a new key-value pair
else {
concise[key] = value;
}
});
console.log(concise);

Here, I assume all attributes are multivalued, then I reduce those that have length 1 to a simple value. This is a bit slower than the reverse approach, where you assume values are singlevalued and promote them to arrays when they prove otherwise, in order to respect the ordering imposed by Instance.
function makeConcise(verbose) {
let concise = {};
verbose.forEach(({Key, Value, Instance}) => {
if (!concise[Key]) concise[Key] = [];
concise[Key][Instance - 1] = Value;
});
Object.keys(concise).forEach(Key => {
if (concise[Key].length == 1) concise[Key] = concise[Key][0];
});
return concise;
}
The reverse function is similarly simple:
function makeVerbose(concise) {
let verbose = [];
Object.keys(concise).forEach(Key => {
if (Array.isArray(concise[Key])) {
concise[Key].forEach((Value, index) => {
verbose.push({Key, Value, Instance: index + 1});
});
} else {
verbose.push({Key, Value: concise[Key], Instance: 1});
}
});
return verbose;
}

const verbose = [{
"Key": "Name",
"Value": "John Doe",
"Instance": 1
},
{
"Key": "Age",
"Value": "33",
"Instance": 1
},
{
"Key": "Child",
"Value": "Jane",
"Instance": 1
},
{
"Key": "Child",
"Value": "Rocky",
"Instance": 2
}
];
let concise = {};
verbose.forEach(item => {
const values = Object.values(item)
if (concise[values[0]]) concise = {...concise, [values[0]]: [concise[values[0]], values[1]]};
else concise = {...concise, ...{[values[0]]: values[1]}}
})

Try this. I have written both conversion functions.
I see other answers only provide only verbose to concise requirement.
let verbose = [{
"Key": "Name",
"Value": "John Doe",
"Instance": 1
},
{
"Key": "Age",
"Value": "33",
"Instance": 1
},
{
"Key": "Child",
"Value": "Jane",
"Instance": 1
},
{
"Key": "Child",
"Value": "Rocky",
"Instance": 2
}
]
let concise = {
"Name": "John Doe",
"Age": "33",
"Child": ["Jane", "Rocky"]
}
verboseToConcise = (verbose) => {
let obj = {}
verbose.forEach(v => {
let key = obj[v.Key]
if (key) typeof key === 'string' ? obj[v.Key] = [key, v.Value] : key.push(v.Value)
else obj[v.Key] = v.Value
})
return obj
}
conciseToVerbose = (concise) => {
let arr = []
Object.entries(concise).forEach(([key, value]) => {
if (typeof value === 'object') {
for (let i = 0; i < value.length; i++){
arr.push({
"Key": key,
"Value": value[i],
"Instance": i+1
})
}
} else {
arr.push({
"Key": key,
"Value": value,
"Instance": 1
})
}
})
return arr
}
console.log(verboseToConcise(verbose))
console.log(conciseToVerbose(concise))

You can do:
const verbose = [{"Key": "Name","Value": "John Doe","Instance": 1},{"Key": "Age","Value": "33","Instance": 1},{"Key": "Child","Value": "Jane","Instance": 1},{"Key": "Child","Value": "Rocky","Instance": 2}];
const concise = Object.values(verbose.reduce((a, {Key, Value}) => (Key === 'Child' ? a.childs[0].Child.push(Value) : a.keys.push({[Key]: Value}), a), {keys: [], childs: [{Child: []}]})).flat(1);
console.log(concise);
.as-console-wrapper { max-height: 100% !important; top: 0; }

I also gave it a try using reduce:
EDIT: Without ... spread syntax, with Object.assign and array.concat
EDIT2: I wanted to try and turn it back again. In this code we lose the value of Instance:(
var verbose = [
{
Key: 'Name',
Value: 'John Doe',
Instance: 1,
},
{
Key: 'Age',
Value: '33',
Instance: 1,
},
{
Key: 'Child',
Value: 'Jane',
Instance: 1,
},
{
Key: 'Child',
Value: 'Rocky',
Instance: 2,
},
]
const concise = verbose.reduce(
(p, n) =>
Object.assign(p, {
[n.Key]: !p.hasOwnProperty(n.Key)
? n.Value
: typeof p[n.Key] === 'string'
? [p[n.Key], n.Value]
: p[n.Key].concat(n.Value),
}),
{},
)
console.log(concise)
// { Name: 'John Doe', Age: '33', Child: [ 'Jane', 'Rocky' ] }
const backAgain = Object.entries(concise).reduce(
(p, [k, v]) =>
Array.isArray(v)
? p.concat(v.map(x => ({ Key: k, Value: x })))
: p.concat({ Key: k, Value: v }),
[],
)
console.log(backAgain)
// [ { Key: 'Name', Value: 'John Doe' },
// { Key: 'Age', Value: '33' },
// { Key: 'Child', Value: 'Jane' },
// { Key: 'Child', Value: 'Rocky' } ]

Related

how to get max value from a nested json array

I have a nested json array and I am trying to get the maximum value of the points attribute in this array.
data = {
"name": "KSE100",
"children": [
{
"name": "TECHNOLOGY & COMMUNICATION",
"children": [
{
"name": "TRG",
'points': -21
},
{
"name": "SYS",
},
]
},
{
"name": "OIL",
"children": [
{
"name": "PPL",
'points': 9
},
{
"name": "PSO",
'points': -19
},
]
},
]
}
I want the max value of points from under the children sections. I mean from under technology and oil sectors.
What I've done so far:
var max;
for (var i in data.children.length) {
for (var j in data.data[i]) {
var point = data.data[i].children[j]
}
}
Try the following:
data = {
"name": "KSE100",
"children": [
{
"name": "TECHNOLOGY & COMMUNICATION",
"children": [
{
"name": "TRG",
'points': -21
},
{
"name": "SYS",
},
]
},
{
"name": "OIL",
"children": [
{
"name": "PPL",
'points': 9
},
{
"name": "PSO",
'points': -19
},
]
},
]
}
var array = [];
for (var first of data.children) {
for (var second of first.children) {
if(second.points != undefined)
{
array.push(second);
}
}
}
var maximumValue = Math.max.apply(Math, array.map(function(obj) { return obj.points; }));
console.log(maximumValue);
you can use the reduce method on the array object to do this
const maxValues = []
data.children.forEach(el => {
if (el.name === 'OIL' || el.name === 'TECHNOLOGY & COMMUNICATIO'){
const max = el.children.reduce((current, previous) => {
if (current.points > previous.points) {
return current
}
}, 0)
maxValues.append({name: el.name, value: max.points})
}
})
This will give you an array of the objects with the name and max value.
First you can convert your object to a string through JSON.stringify so that you're able to use a regular expression
(?<=\"points\":)-?\\d*
To matchAll the values preceded by the pattern \"points\": that are or not negative values. After it, convert the result to a array through the spread operator ... and then reduce it to get the max value.
const data = {name:"KSE100",children:[{name:"TECHNOLOGY & COMMUNICATION",children:[{name:"TRG",points:-21},{name:"SYS"}]},{name:"OIL",children:[{name:"PPL",points:9},{name:"PSO",points:-19}]}]};
console.log(
[ ...JSON.stringify(data).matchAll('(?<=\"points\":)-?\\d*')]
.reduce((acc, curr) => Math.max(curr, acc))
)
I wasn't 100% sure, what your exact goal is, so I included a grouped max value and and overall max value with a slight functional approach.
Please be aware that some functionalities are not working in older browsers i.e. flatMap. This should anyways help you get started and move on.
const data = {
name: "KSE100",
children: [
{
name: "TECHNOLOGY & COMMUNICATION",
children: [
{
name: "TRG",
points: -21,
},
{
name: "SYS",
},
],
},
{
name: "OIL",
children: [
{
name: "PPL",
points: 9,
},
{
name: "PSO",
points: -19,
},
],
},
],
};
const maxPointsByGroup = data.children.reduce(
(acc, entry) => [
...acc,
{
name: entry.name,
max: Math.max(
...entry.children
.map((entry) => entry.points)
.filter((entry) => typeof entry === "number")
),
},
],
[]
);
console.log("grouped max:", maxPointsByGroup);
const overallMax = Math.max(
...data.children
.flatMap((entry) => entry.children.flatMap((entry) => entry.points))
.filter((entry) => typeof entry === "number")
);
console.log("overall max:", overallMax);

Call object per their ids and append the result to a big final object [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
As per title I have this array of objects:
myArr=[ {
"id": "25a91eccf70ae3eb",
"name": "ParentID",
},
{
"id": "25a91eccf70ae3eb",
"name": "Child1",
},
{
"key": "25a91eccf70ae3eb",
"name": "Child2",
}]
And would like to have each object named with is own id and append them to a big object in the following format
myBigObject={
ParentID:{
id: "ParentID",
name: "Parent",
},
child1_ID:{
id: "child1_ID",
name: "Child1",
},
child2_ID:{
id: "child2_ID",
name: "Child2",
}
How can I achieve that?
Thanks
Here is the simple readable solution:
var myArr = [{
"key": "25a91eccf71ae3eb",
"name": "ParentID",
},
{
"key": "25a91eccf72ae3eb",
"name": "Child1",
},
{
"key": "25a91eccf73ae3eb",
"name": "Child2",
}
]
let finalObj = {}
const first_node = myArr[0];
for (let item of myArr) {
finalObj[item.key] = { 'id': item.key, "name": item.name };
if (item.key == first_node.key) {
finalObj[item.key].ChildrenID = [];
continue;
}
finalObj[first_node.key].ChildrenID.push(item.key);
}
console.log(finalObj);
In your question, the sample object has the values for every 'key' property as same. I have changed that assuming all the keys would be different. Please check the solution below -
const myArr=[
{
"key": "123",
"name": "ParentID",
},
{
"key": "456",
"name": "Child1",
},
{
"key": "789",
"name": "Child2",
}];
function modifyArray(arr) {
return arr.reduce((resultObj, currObj, index) => {
resultObj = {
...resultObj,
[currObj.key]: {
id: currObj.key,
name: currObj.name
}
}
return resultObj;
}, {});
}
const arr1 = modifyArray(myArr);
console.log(arr1);
U can use Object.assign() and map() to accomplish this.
const myArr = [
{
"id": "25a91eccf70ae3eb",
"name": "ParentID",
},
{
"id": "25a91eccf70ae3eb",
"name": "Child1",
},
{
"id": "25a91eccf70ae3eb",
"name": "Child2",
}
];
const arrMap = myArr.map(({ id, name }, i) => {
return i === 0 ? // if loop is at first element
{ parent_ID: { id, name } } : // return parent
{ [`child${i}_ID`]: { id, name } }; // otherwise corresponding child
});
const result = Object.assign({}, ...arrMap); // assign to object
console.log(result);
Seems like most of what you're after can be accomplished using the .forEach() method to run a specific function over every element of the array (this will be where you change the contents) and then adding the resulting object into your big output object.

how to make nested array objects in javascript in a key value pair format

array data=[
{
"id":1,
"name":"john",
"income":22000,
"expenses":15000
},
{
"id":2,
"name":"kiran",
"income":27000,
"expenses":13000
},
{
"id":1,
"name":"john",
"income":35000,
"expenses":24000
}
]
i want to make a new array set in following format which is in a key value pair. ie result set.
can you please explain the best method. ? how to achive using foreach.?
tried using foreach method by looping each element. but cant get the desired output format
var result= [ {
"name": "john",
"series": [
{
"name": "income",
"value": 22000
},
{
"name": "expenses",
"value": 15000
},
]
},
{
"name": "kiran",
"series": [
{
"name": "income",
"value": 27000
},
{
"name": "expenses",
"value": 13000
},
]
}]
// Your array
const result = [
{
name: "john",
series: [
{
name: "income",
value: 22000,
},
{
name: "expenses",
value: 15000,
},
],
},
{
name: "kiran",
series: [
{
name: "income",
value: 27000,
},
{
name: "expenses",
value: 13000,
},
],
},
];
// What is .map function?
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
// Output
// map return a new function.
// it's a loop method but more equipped
result.map((item, index) => {
const seriesKeyValues = {};
// forEach is too, it's a loop method.
// but not have a return value,
// just loops and give you item on each loop
item.series.forEach(serie => {
//seriesKeyValues is a object.
// different between seriesKeyValues.serie.name
// it's a bracket notation
// look this documentation
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names
seriesKeyValues[serie.name] = serie.value;
});
// return new Object
// ... is 'spread syntax' basically combine objects
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#spread_properties
// spread syntax is a new way.
// old way is https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
return {
id: index,
name: item.name,
...seriesKeyValues,
};
});
I hope it will help :). if you don't understand any lines of code, i can explain

Javascript -sort array based on another javascript object properties

I have one javascript array and one object . Need help to sort javascript object keys based on the order number in another array
In subgroup array , I have name , order number. Need to sort Offerings keys based on that order number
const subgroup = [
{
"code": "6748",
"name": "test123",
"orderNumber": "0"
},
{
"code": "1234",
"name": "customdata",
"orderNumber": "1"
}
]
const offerings = {
"customdata" : [
{
"code": "Audi",
"color": "black"
}
],
"test123" : [
{
"brand": "Audi",
"color": "black"
}
]
}
I believe this should work for you. I've added some comments in the code that should hopefully do an okay job of explaining what is happening.
var subgroup = [{
"code": "6748",
"name": "test123",
"orderNumber": "0"
}, {
"code": "1234",
"name": "customdata",
"orderNumber": "1"
}];
var offerings = {
"customdata": [{
"code": "Audi",
"color": "black"
}],
"test123": [{
"brand": "Audi",
"color": "black"
}]
}
function sortObjectFromArray(refArray, sortObject, orderKey = 'order', linkKey = 'key') {
// Get copy of refArray
let reference = refArray.slice();
// Sort sortObject [ into an array at this point ]
let sorted = [];
for (let key in sortObject) {
// Searches the refArray for the linkKey, and returns the intended index
let index = reference.find((item) => item[linkKey] === key)[orderKey];
// Places the sortObject's value in the correct index of the 'sorted' Array
sorted[parseInt(index)] = [key, sortObject[key]];
};
// Return an object, created from previous 'sorted' Array
return sorted.reduce((obj, [key, value]) => {
obj[key] = value;
return obj;
}, {});
};
offerings = sortObjectFromArray(subgroup, offerings, 'orderNumber', 'name');
console.log(offerings);

Javascript underscore data format array of object

By using underscoreJS lib and manipulating some datas, i have this object
var data = {
"2017-09-26": [
{
"id": 274281,
"value": 10
},
{
"id": 274282,
"value": 20
}],
"2017-09-27": [
{
"id": 274281,
"value": 12
},
{
"id": 274282,
"value": 13
}],
}
i would like to obtain this result below by passing the keys as date in the child object and transform the value of id key as the new key of the value of value
var data = [{
date:"2017-09-26",
274281: 10,
274282: 20
},
{
date:"2017-09-27",
274281: 12,
274282: 13
}]
Please does someone as an idea to help me to do this and ideally efficiently?
Thanks
Here it is in one line:
Object.keys(data).map(key => ({date: key, ...data[key].reduce((p, c) => {p[c.id] = c.value; return p}, {})}))
Result:
[{
"274281":10,
"274282":20,
"date":"2017-09-26"
},
{
"274281":12,
"274282":13,
"date":"2017-09-27"
}]
You need nested loops. The first level creates the objects with the date property, then you loop over the objects in that value, and add the id: value properties to the result.
var newdata = _.map(data, (date, objects) => {
res = {date: date};
_.each(objects, obj => {
res[obj.id] = obj.value;
});
return res;
});
You can use Array.from() on the result of Object.entries(data) to create an array of objects by passing a callback function as the second argument.
Then for each sub-array, use .reduce() to create a new object from its members.
var data = {
"2017-09-26": [
{ "id": 274281, "value": 10 },
{ "id": 274282, "value": 20 }
],
"2017-09-27": [
{ "id": 274281, "value": 12 },
{ "id": 274282, "value": 13 }
],
};
const result = Array.from(Object.entries(data), ([key, arr]) =>
arr.reduce((res, {id, value}) =>
Object.assign(res, {[id]: value})
, {date: key})
);
console.log(result);
Here's one that's just about the same, but uses the new object literal spread syntax.
var data = {
"2017-09-26": [
{ "id": 274281, "value": 10 },
{ "id": 274282, "value": 20 }
],
"2017-09-27": [
{ "id": 274281, "value": 12 },
{ "id": 274282, "value": 13 }
],
};
const result = Array.from(Object.entries(data), ([key, arr]) =>
({date: key,
...Object.assign({}, ...arr.map(({id, value}) => ({[id]: value})))
})
);
console.log(result);

Categories

Resources