Google Apps Script function to denormalize json data working erratically - google-apps-script

I have a function to denormalize json data.
Json data looks like:
-entries
- entry
- skus
What I am trying to do is to create an array of objects where entries with more than 1 SKUs should be repeated the x times, where x is the number of skus (length of the sku array); each time switching the data of the skus.
The problem is that the sku data does not switch, and the same skus are shown multiple times in the resulting array.
When I debug step by step, the array is appended fine at the beginning, however when function proceeds the correctly appended elements of the array are overwritten.
Here the function code:
let data = [
{
name: 'a',
skus: [1, 2],
},
{
name: 'b',
skus: [3, 4],
},
{ name: 'c', skus: [5] },
{ name: 'd', skus: [6, 7, 8] },
];
function flatten(data) {
let newArray = [];
for (i in data) {
const el = {};
el.name = data[i].name;
let skus = data[i].skus;
for (j in skus) {
el.sku = skus[j];
newArray.push(el);
console.log(el);
}
}
return newArray;
}
what I am trying to achieve is to return a new array which is so:
[
{ name: a,
sku: 1
},
{ name: a,
sku: 2
},
{
name: b,
sku: 3,
},
{
name: b,
sku: 4,
}... and so on ]
Thanks

You want to achieve the following conversion.
From
const data = [
{name: 'a', skus: [1, 2]},
{name: 'b', skus: [3, 4]},
{name: 'c', skus: [5]},
{name: 'd', skus: [6, 7, 8]},
];
To
[
{"name": "a", "sku": 1},
{"name": "a", "sku": 2},
{"name": "b", "sku": 3},
{"name": "b", "sku": 4},
,
,
,
]
Modification points:
I think that the reason of your issue is due to the call by reference. When the object el is put to the array with newArray.push(el), el is changed by the next loop. By this, I think that your issue occurs. In this case, it is required to copy the object and put to the array.
When above points are reflected to your script, it becomes as follows.
Modified script:
From:
newArray.push(el);
To:
newArray.push(Object.assign({}, el));
Testing:
let data = [
{name: 'a', skus: [1, 2]},
{name: 'b', skus: [3, 4]},
{name: 'c', skus: [5]},
{name: 'd', skus: [6, 7, 8]},
];
function flatten(data) {
let newArray = [];
for (i in data) {
const el = {};
el.name = data[i].name;
let skus = data[i].skus;
for (j in skus) {
el.sku = skus[j];
newArray.push(Object.assign({}, el));
// console.log(el);
}
}
return newArray;
}
console.log(flatten(data))
Other pattern:
In your case, the following script can be also used.
const data = [
{name: 'a', skus: [1, 2]},
{name: 'b', skus: [3, 4]},
{name: 'c', skus: [5]},
{name: 'd', skus: [6, 7, 8]},
];
const res = data.reduce((ar, {name, skus}) => {
skus.forEach(e => ar.push({name: name, sku: e}));
return ar;
}, []);
console.log(res);
Reference:
Object.assign()

Related

Merging duplicated data objects from the response

I have a api response as given below
response = [
{ id: 1, val: 'A', date: '28/03/2021', versions: [] },
{ id: 1, val: 'B', date: '29/03/2021', versions: [] },
{ id: 1, val: 'C', date: '30/03/2021', versions: [] },
{ id: 2, val: 'D', date: '31/03/2021', versions: [] }
]
Clearly, id: 1's latest value is C. I need to transform it as given below
response = [
{ id: 2, val: 'D', date: '31/03/2021', versions: ['31/03/2021'] },
{ id: 1, val: 'C', date: '30/03/2021', versions: ['28/03/2021', '29/03/2021', '30/03/2021'] }
]
which means, id:1 has three versions and id:2 has only one version.
I tried something like this
_.uniqBy(_.orderBy(response, 'date','desc'), 'id');
the above code removed the duplicates and showed the latest id:1's value, but not sure which lodash function to use and how to add the versions. Any leads would be very helpful.
Try like this:
let result = [];
let uniqueIds = [...new Set(response.map(x => x.id))];
uniqueIds.forEach(id => {
let items = [...response.filter(x => x.id == id)];
var maxDate = new Date(Math.max.apply(null, items.map(y => new Date(y.date))));;
result.push({
id: id,
date: maxDate,
versions :[...items.map(y => y.date)]
});
});
Check Demo

How to add new row next to existing row having similar key in json

I have two variables having json data as below.
var json1=
[{ name: 'AAA', id: 100},
{ name: 'BBB', id: 100 },
{ name: 'CCC', id: 101},
{ name: 'DDD', id: 102} ]
var json2=
[ { name: 'EEE', id: 101}
]
I need get combination of both variables as below.
var jsonCombined=
[{ name: 'AAA', id: 100},
{ name: 'BBB', id: 100 },
{ name: 'CCC', id: 101},
{ name: 'EEE', id: 101},
{ name: 'DDD', id: 102} ]
I tried to concatenate ,but it added to the last position.
Any help willbe appreciated.
Method one
If you know that json1 is already sorted by id values then you could iterate through the objects in json2 and use the .splice method to insert them.
var json1=
[{ name: 'AAA', id: 100},
{ name: 'BBB', id: 100 },
{ name: 'CCC', id: 101},
{ name: 'DDD', id: 102} ]
var json2=
[ { name: 'EEE', id: 101}
]
var jsonCombined = json1.slice(); //make a copy of json1
for (let obj of json2) {
for (let i = 0; i < jsonCombined.length; i++) {
if (jsonCombined[i]['id'] == obj['id']) {
jsonCombined.splice(i + 1, 0, obj);
break;
}
}
}
console.log(jsonCombined);
Method two
On the other hand, if you do not know that json1 is sorted then you can just combine the two json arrays and sort the objects based on their ids.
var json1=
[{ name: 'AAA', id: 100},
{ name: 'BBB', id: 100 },
{ name: 'CCC', id: 101},
{ name: 'DDD', id: 102} ]
var json2=
[ { name: 'EEE', id: 101}
]
var jsonCombined = json1.concat(json2).sort((a,b) => a['id'] > b['id'] ? 1 : -1);
console.log(jsonCombined);
try this
var combinedjson = [...json1, ...json2].sort((a, b) => a.id > b.id ? 1 : -1);

How to transpose array of objects in TypeScript?

I am having an array of objects as below:
finalList = [
[{name: john}, {name: max}, {name: rob}],
[{id: 1}, {id: 2}, {id: 3}],
[{gender: M}, {gender: F}, {gender: M}],
]
I need the array to transpose like this:
finalList = [
{name: john, id: 1, gender: M},
{name: john, id: 1, gender: M},
{name: john, id: 1, gender: M}
]
The actual array of object is in nested array. Please help me guiding to transpose the array in TypeScript.
Here's a nice functional way. It assumes each array in finalList has the same length and same keys (so no error handling).
const finalList = [
[{name: "john"}, {name: "max"}, {name: "rob"}],
[{id: 1}, {id: 2}, {id: 3}],
[{gender: "M"}, {gender: "F"}, {gender: "M"}],
];
console.log(finalList);
// this is a trick to create an array of a specific size with unique objects inside it
// the fill is necessary to iterate over the holed array (https://stackoverflow.com/q/40297442/2178159)
// fill({}) won't work since it's a single object ref that will be shared
const results = new Array(finalList.length).fill(null).map(() => ({}));
finalList.forEach(group => {
group.forEach((obj, i) => {
Object.assign(results[i], obj);
})
});
console.log(results);

Adding single element to an immutable list

i want to just add an element to a list somewhere in my immutable object tree.
This question appears to have been answered here :
Append value to List
But for some reason it does not work for me.
If I have the following code :
var myState = {
a: {
b: {
c: [
{name: 'hi', value: 2},
{name: 'howdy', value: 3}
]
}
}
}
myState = Immutable.fromJS(myState);
myState = myState.update(['a', 'b', 'c'], function (myList) {
myList.push({"name": "hallo", "value": 4})
}
);
I get an error :
Uncaught TypeError: Cannot read property 'push' of undefined
which indicates that the myList parameter being passed into the callback is null.
Why is this happening?
fiddle:
https://codepen.io/owatkins/pen/brMava
This is how it should be written:
myState.updateIn(['a', 'b', 'c'], function (myList) {
return myList.push({"name": "hallo", "value": 4})
}
);
Below is a working example:
var myState = Immutable.fromJS({
a: {
b: {
c: [{
name: 'hi',
value: 2
},
{
name: 'howdy',
value: 3
}
]
}
}
})
myState = myState.updateIn(['a', 'b', 'c'], function(myList) {
return myList.push({
"name": "hallo",
"value": 4
})
});
console.info('myState = ' + myState.toJS())
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script>
notice that I'm using updateIn instead of update and returning the result of push
After much stuffing around, the only solution I could come up with is to get the array, and convert to JS, push an element onto it, then convert it back to an immutable... and then use setIn, NOT updateIn, and NOT update.
var myState = {
a: {
b: {
c: [
{name: 'hi', value: 2},
{name: 'howdy', value: 3}
]
}
}
}
myState = Immutable.fromJS(myState);
var list = myState.getIn(['a', 'b', 'c'])
var list = list.toJS();
list.push({"name": "hallo", "value": 4});
var v = Immutable.fromJS(list)
myState = myState.setIn(['a', 'b', 'c'], v)
This looks like a horrible solution, but it is the only thing that works for me so far.
Usually it takes about 5 minutes to learn how to add an element to a list in a framework or language.
I wasn't expecting it to take 5 HOURS.
The documentation for this framework is an absolute disgrace.

Trouble formatting json objects with lodash _.groupBy

I'm having trouble reformatting an object in order to group by lists.
// input
{
'M': [
{name: Bob, id: 1},
{name: John, id: 2},
{name: John, id: 3},
],
'F': [
{name: Liz, id: 4},
{name: Mary, id: 5},
{name: Mary, id: 6},
]
}
// desired output
{
'M': [
'Bob': [ {name: Bob, id: 1},]
'John': [ {name: John, id: 2}, {name: John, id: 3} ]
],
'F': [
'Liz': [ {name: Liz, id: 4} ]
'Mary': [ {name: Mary, id: 5}, {name: Mary, id: 6} ]
]
}
My current script is only returning the 'M' key and I'm not what is causing it
for (var key in obj) {
var data = _.groupBy(obj[key], 'name')
return data;
}
I've also tried
Object.keys(obj).forEach(obj, key => {
var data = _.groupBy(obj[key], 'name')
return data;
})
but it throws TypeError: #<Object> is not a function
You can use mapValues to group each gender groups by their names through groupBy.
var output = _.mapValues(input, names => _.groupBy(names, 'name'));
var input = {
'M': [
{name: 'Bob', id: 1},
{name: 'John', id: 2},
{name: 'John', id: 3},
],
'F': [
{name: 'Liz', id: 4},
{name: 'Mary', id: 5},
{name: 'Mary', id: 6},
]
};
var output = _.mapValues(input, names => _.groupBy(names, 'name'));
console.log(output);
body > div { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
Use _.forOwn since you want to iterate its own properties.
_.forOwn(obj, function(key, val) {
var ret = {};
ret[key] = _.groupBy(val, 'name');
return ret;
});