Grouping the Json object with multiple objects - javascript

I need to group by sector and company-name of below json object.
original JSON object:
data =[
{"sector":"IT",
"company-name": "ABC",
"contact": "Person1",
"position":"Accountant"
},
{"sector":"IT",
"company-name": "ABC",
"contact": "Person2",
"position":"Accountant"
},
{"sector":"IT",
"company-name": "ABC2",
"contact": "Person1",
"position":"Accountant"
},
{"sector":"IT",
"company-name": "ABC2",
"contact": "Person2",
"position":"Accountant"
},
{"sector":"IT",
"company-name": "ABC2",
"contact": "Person3",
"position":"Accountant"
},
{"sector":"Finance",
"company-name": "Fin1",
"contact": "Person3",
"position":"Accountant"
}
]
output:
I could able to group by one i.e. company-name.Not how to extend this dynamically for multiple groups.
const result = {};
const groubyfiled = 'company-name'
this.data.foreach((item: any) => {
const gname = item[groubyfiled];
result[gname] = result[gname] || {};
result[gnmae].items = result[gname].items || [];
result[gname].items.push(item);
});
output:
{
"IT": {
"ABC": {...},
"ABC2": {...}
},
"Finance" : {
"Fin1":{....}
}
}

You can write a function that groups items by a single key.
function groupBySingleField(data, field){
return data.reduce((acc, val) => {
const rest = Object.keys(val).reduce((newObj, key) => {
if(key !== field){
newObj[key] = val[key]
}
return newObj;
}, {});
if (acc[val[field]]) {
acc[val[field]].push(rest);
} else {;
acc[val[field]] = [rest];
}
return acc;
}, {})
}
And then write a recursive function to additionally group already grouped items with a different key.
function groupByMultipleFields(data,...fields){
if(fields.length === 0 ) return;
let newData = {};
const [field] = fields;
newData = groupBySingleField(data, field);
const remainingFields = fields.slice(1);
if(remainingFields.length > 0){
Object.keys(newData).forEach((key) => {
newData[key] = groupByMultipleFields(newData[key],...remainingFields)
})
}
return newData;
}
You can try the code snippet here itself, to see if this is the result you are expecting
data = [
{
sector: "IT",
"company-name": "ABC",
contact: "Person1",
position: "Accountant"
},
{
sector: "IT",
"company-name": "ABC",
contact: "Person2",
position: "Accountant"
},
{
sector: "IT",
"company-name": "ABC2",
contact: "Person1",
position: "Accountant"
},
{
sector: "IT",
"company-name": "ABC2",
contact: "Person2",
position: "Accountant"
},
{
sector: "IT",
"company-name": "ABC2",
contact: "Person3",
position: "Accountant"
},
{
sector: "Finance",
"company-name": "Fin1",
contact: "Person3",
position: "Accountant"
}
];
function groupBySingleField(data, field){
return data.reduce((acc, val) => {
const rest = Object.keys(val).reduce((newObj, key) => {
if(key !== field){
newObj[key] = val[key]
}
return newObj;
}, {});
if (acc[val[field]]) {
acc[val[field]].push(rest);
} else {;
acc[val[field]] = [rest];
}
return acc;
}, {})
}
console.log("Grouping by single fields");
console.log("Grouping by sector");
console.log(groupBySingleField(data, "sector"));
console.log("Grouping by company-name");
console.log(groupBySingleField(data, "company-name"));
function groupByMultipleFields(data,...fields){
if(fields.length === 0 ) return;
let newData = {};
const [field] = fields;
newData = groupBySingleField(data, field);
const remainingFields = fields.slice(1);
if(remainingFields.length > 0){
Object.keys(newData).forEach((key) => {
newData[key] = groupByMultipleFields(newData[key],...remainingFields)
})
}
return newData;
}
console.log("Grouping by multiple fields");
console.log("Grouping by company-name and position");
console.log(groupByMultipleFields(data,"company-name", "position"));
console.log("Grouping by position");
console.log(groupByMultipleFields(data,"position"));
console.log("Grouping by sector, company-name and position");
console.log(groupByMultipleFields(data,"sector", "company-name", "position"));

To get the output you're looking for, you could use something like this:
const result = {};
// loop through each object in data array
data.forEach(function(obj){
// create sector property if it doesn't exist
if (!result.hasOwnProperty(obj.sector)) result[obj.sector] = {};
// create company_name property within sector if it doesn't exist
if (!result[obj.sector].hasOwnProperty(obj.company_name)) result[obj.sector][obj.company_name] = {}
// set contact and position properties
result[obj.sector][obj.company_name]['contact'] = obj.contact;
result[obj.sector][obj.company_name]['position'] = obj.position;
});
console.log(result);
This code relies on each object in your data array having the same structure and properties. I'm not sure if you need your code to be more flexible.
Please check out the comments in the code to see exactly how it works.
Also, one important change is that you cannot use a hyphen in your property names. JS may interpret those as a minus sign when you're accessing properties. For that reason, you'll need to repace company-name with company_name in your data array for this code to work!

Related

moving a key value pair out of an array

I am trying to move everything in the Array Results outside and into the original object
this is the object
{
"Name": "John",
"Results": [
{
"Type": "DB",
"Immediate_Action": "No",
}
]
}
It should look like this
{
"Name": "John",
"Type": "DB",
"Immediate_Action": "No",
}
What I have so far is this
const mapOscarResults = ({ data }) => {
return data.map(entry => {
let mapped = {...entry};
entry.Results.forEach(key => {
let Type = mapped[key.Type]
if (mapped[key]) {
mapped[key].push(entry.Results[key]);
} else {
mapped[key] = [entry.Results[key]];
}
});
return mapped;
});
};
You can simply spread the Results array into an Object.assign() call.
const input = { "Name": "John", "Results": [{ "Type": "DB", "Immediate_Action": "No", }, { "Another": "value" }] };
const { Results, ...refactored } = input;
Object.assign(refactored, ...Results);
console.log(refactored)
This code works for your example:
const { Results: results, ...rest } = {
"Name": "John",
"Results": [
{
"Type": "DB",
"Immediate_Action": "No",
}
]
}
const res = {...rest, ...results.reduce((prev, curr) => ({
...prev,
...curr
}), {})}
console.log(res)
But I don't know what you expect when the Results array has more than one element.
In that condition, if this code does not fill your needs, ask me to change it.
however, it will join first Result with index 0, you can expand it
const data = {
"Name": "John",
"Results": [
{
"Type": "DB",
"Immediate_Action": "No",
}
]
}
const mapOscarResults = (data) => {
for (let i in Object.keys(data)){
if (Array.isArray(data[Object.keys(data)[i]])){
newKey = data[Object.keys(data)[i]][0]
data = {... data, ...newKey}
delete data[Object.keys(data)[i]]
}
}
return data
};
console.log(mapOscarResults(data))

Renaming keys in an object using reduce method in JS

Following is the object in which I want to replace countryID with value, countryName with label.
In the same object I am having localLanguages Array in which I am trying to rename language with label and languageCode with value.
array -
var obj = [{
"countryID": "CON1010",
"countryName": "Poland",
"countryCode": "pl",
"localLanguages": [{
"language": "English",
"languageCode": "en"
},
{
"language": "Polish",
"languageCode": "en"
}
]
},
{
"countryID": "CON1011",
"countryName": "UK",
"countryCode": "uk",
"localLanguages": [{
"language": "English",
"languageCode": "en"
}]
}
];
Transformed to -
var obj = [{
"value": "CON1010",
"label": "Poland",
"countryCode": "pl",
"localLanguages": [{
"label": "English",
"value": "en"
},
{
"label": "Polish",
"value": "en"
}
]
},
{
"value": "CON1011",
"label": "UK",
"countryCode": "uk",
"localLanguages": [{
"label": "English",
"value": "en"
}]
}
];
Code -
arr.map(x => {
var newObj = Object.keys(x).reduce((obj, key) => {
if (key !== 'countryID') {
obj[key] = x[key]
}
if (key === 'countryID') {
obj.value = x.countryID;
}
}, {})
console.log(newObj);
return newObj;
})
Here is a solution with es6 Destructuring and map:
const arr = [{"countryID":"CON1010","countryName":"Poland","countryCode":"pl","localLanguages":[{"language":"English","languageCode":"en"},{"language":"Polish","languageCode":"en"}]},{"countryID":"CON1011","countryName":"UK","countryCode":"uk","localLanguages":[{"language":"English","languageCode":"en"}]}];
const result = arr.map(item => {
let localLanguages = item.localLanguages.map(i => {
const { language: label, languageCode: value, ...rest } = i;
return { label, value, ...rest };
});
const { countryID: value, countryName: label, ...rest } = item;
return { value, label, ...rest, localLanguages };
});
console.log(result)
Use Array.map() to convert the outer objects, and another map to convert the localLanguages:
const arr = [{"countryID":"CON1010","countryName":"Poland","countryCode":"pl","localLanguages":[{"language":"English","languageCode":"en"},{"language":"Polish","languageCode":"en"}]},{"countryID":"CON1011","countryName":"UK","countryCode":"uk","localLanguages":[{"language":"English","languageCode":"en"}]}];
const result = arr.map(o => ({
value: o.countryID,
label: o.countryName,
countryCode: o.countryCode,
localLanguages: o.localLanguages.map(l => ({
value: l.languageCode,
label: l.language
}))
}));
console.log(result)
You have forgotten to return obj value in the reduce function
var newObj = Object.keys(x).reduce( (obj, key) => {
if(key !== 'countryID') {
obj[key] = x[key]
}
if(key === 'countryID') {
obj.value = x.countryID;
}
}, {})
Here the function to change the keys. Use it with every element of you arrayrecursively, but check the type of every element
function changeKeys(obj) {
const rename = {
'countryID': 'value',
'countryName': 'label',
'language': 'label',
'languageCode': 'value'
}
return Object.keys(obj)
.reduce(
(acc, rec) => {
if (typeof rename[rec] !== 'undefined') {
return {...acc, [rename[rec]]: obj[rec]}
}
return {...acc, [rec]: obj[rec]}
}, {}
)
}

Group by using same key and join value with comma

I have the following sample data with dynamic key /value pair, i need to group them with same key , joining mutiple value by comma. I was able to extract unique keys on array and then stuck
input
[
{
"c1": "USA"
},
{
"c2": "Korea"
},
{
"c4": "japan"
},
{
"c3": "india"
},
{
"c1": "australia"
},
{
"c2": "france"
}
]
output
[
{
"c1": "USA,australia",
"c2": "Korea,france",
"c4": "japan",
"c3": "india"
}
]
let data=[
{
"c1": "USA"
},
{
"c2": "Korea"
},
{
"c4": "japan"
},
{
"c3": "india"
},
{
"c1": "australia"
},
{
"c2": "france"
}
]
var output = Object.keys(data).map(element => {
var ret = Object.keys(data[element]);
return ret;
})
let c=[...new Set(output.flat())];
console.log(c);
How to join the values by comma from the unique array i got, i think i am halfway
you'll need to output a new organized object with the help of your map() function.
didn't check the code - but it should look something like this.
let dataNew = {};
var output = Object.keys(data).map(element => {
if (typeof( dataNew[element] ) === 'undefined') {
dataNew[element] = data[element]
} else {
dataNew[element] += `,${data[element]}`;
}
return dataNew;
})
like this you are creating a new object with comas in unified values.
You could try Array.reduce prototype
let data=[
{
"c1": "USA"
},
{
"c2": "Korea"
},
{
"c4": "japan"
},
{
"c3": "india"
},
{
"c1": "australia"
},
{
"c2": "france"
}
]
const combinedData = data.reduce((memory, current) => {
const currentKeys = Object.keys(current);
const found = memory.find(m =>
Object.keys(m).some(key => currentKeys.includes(key))
);
if (found) {
const key = Object.keys(found).pop();
found[key] = `${found[key]},${current[key]}`;
} else {
memory.push(current);
}
return memory;
}, []);
console.log(combinedData);
Take the key value pairs, flatten them (as it does not matter wether the keys where in the same object or not), then merge using another object:
const result = input
.map(Object.entries)
.flat()
.reduce((obj, [k, v]) => ((obj[k] = obj[k] ? (obj[k] + ", " + v) : v), obj), {});
Sorry i went back and de-duped the final Array.
const data = [
{
"c1": "USA"
},
{
"c2": "Korea"
},
{
"c4": "japan"
},
{
"c3": "india"
},
{
"c1": "australia"
},
{
"c2": "france"
}
]
let endData = [{}]
data.forEach(d => {
const [dataKey] = Object.keys(d)
const relatedValues = data.map(d => dataKey in d ? d[dataKey] : null).filter(Boolean)
const combinedValues = [d[dataKey], ...relatedValues]
const unique = endData.find(d => Object.keys(d)[0] === dataKey) === undefined
if (unique) endData[0][dataKey] = `${[...new Set(combinedValues)]}`
})
console.log(endData)
Without changing your code:
iterate over each value of Set c, then filter the data items that have the same key, then merge them with join (',').
let data=[
{
"c1": "USA"
},
{
"c2": "Korea"
},
{
"c4": "japan"
},
{
"c3": "india"
},
{
"c1": "australia"
},
{
"c2": "france"
}
]
var output = Object.keys(data).map(element => {
var ret = Object.keys(data[element]);
return ret;
})
let c=[...new Set(output.flat())];
/* Join equals */
const n = [];
c.forEach( (it, idx) => {
n.push({});
n[idx][it] = data.filter(its => it === Object.keys(its)[0])
.map( its => Object.values(its)[0])
.join(',');
})
console.log(n);

Build array from another array if some key are identical using JavaScript

I have an array of data. Some of the key in the array are same. I would like to create a new array based on the key and add the other data.
This is my array
var myObjOne = [
{
"name":"John",
"id":1,
"car":"maruti"
},
{
"name":"John",
"id":2,
"car":"wolks"
},
{
"name":"John",
"id":3,
"car":"bmw"
},
{
"name":"Peter",
"id":4,
"car":"alto"
},
{
"name":"Peter",
"id":5,
"car":"swift"
}
];
I would like to convert the array in to the below format.
var myObj = [
{
"name":"John",
"items": [
{ "id":1, "car":"maruti" },
{ "id":2, "car":"wolks" },
{ "id":3, "car":"bmw" }
]},
{
"name":"Peter",
"items": [
{ "id":4, "car":"alto" },
{ "id":5, "car":"swift" },
]
}
];
I am working on a node environment.
You can create an object using Array#reduce first which maps name with items, and then create the final array by looping over the intermediate map using a for...of loop:
var source = [{"name":"John","id":1,"car":"maruti"},{"name":"John","id":2,"car":"wolks"},{"name":"John","id":3,"car":"bmw"},{"name":"Peter","id":4,"cars":"alto"},{"name":"Peter","id":5,"cars":"swift"}];
const map = source.reduce((acc, {name, ...obj}) => {
if (!acc[name]) {
acc[name] = [];
}
acc[name].push(obj);
return acc;
}, {});
const result = [];
for (let[name, items] of Object.entries(map)) {
result.push({name, items});
}
console.log(result);
Array.reduce is at rescue.This method accepts an accumulator and current
item. Check in the accumulator if there exist an object where the value of name property is John or Peter
var myObjOne = [{
"name": "John",
"id": 1,
"car": "maruti"
},
{
"name": "John",
"id": 2,
"car": "wolks"
},
{
"name": "John",
"id": 3,
"car": "bmw"
},
{
"name": "Peter",
"id": 4,
"car": "alto"
},
{
"name": "Peter",
"id": 5,
"car": "swift"
}
];
var newObj = myObjOne.reduce(function(acc, curr, currIndex) {
// using findIndex to check if there exist an object
// where the value of the name property is John, Peter
// if it exist it will return the index else it will return -1
let ifNameExist = acc.findIndex(function(item) {
return item.name === curr.name;
})
// if -1 then create a object with name and item property and push
// it to the accumulator
if (ifNameExist === -1) {
let nameObj = {};
nameObj.name = curr.name;
nameObj.items = [];
nameObj.items.push({
id: curr.id,
car: curr.car
})
acc.push(nameObj)
} else {
// if such an object already exist then just update the item array
acc[ifNameExist].items.push({
id: curr.id,
car: curr.car
})
}
return acc;
}, []);
console.log(newObj)
Use .reduce to group by name, and use .find inside the reducer to find if the matching name has already been added:
const input=[{"name":"John","id":1,"car":"maruti"},{"name":"John","id":2,"car":"wolks"},{"name":"John","id":3,"car":"bmw"},{"name":"Peter","id":4,"cars":"alto"},{"name":"Peter","id":5,"cars":"swift"}]
const output = input.reduce((a, { name, ...item }) => {
const foundNameObj = a.find(nameObj => nameObj.name === name);
if (foundNameObj) foundNameObj.items.push(item);
else a.push({ name, items: [item] });
return a;
}, []);
console.log(output);

How can I remove the parent keys from a javascript Object?

I currently have this Object:
schoolsObject = [{
"college_1":
{
"id":"college_1",
"location":"Victoria",
"name":"College One"
},
"college_2":
{
"id":"college_2",
"location":"Tasmania",
"name":"College Two"
}
}];
I want to remove the top level keys ie. college_1, college_2 and 'flatten' the object out like this, so I have no 'top level' keys:
flatSchoolsObject =
[{
"id":"college_1",
"location":"Victoria",
"name":"College One"
},
{
"id":"college_2",
"location":"Tasmania",
"name":"College Two"
}];
Here is my latest attempt, I've made a lot of different try's but have not been documenting them:
// schoolIDs = Object.keys(schoolsObject);
var schools = {};
for(var i=0; i<Object.keys(schoolsObject).length; i++){
for (var property in schoolsObject) {
if (schoolsObject.hasOwnProperty(property)) {
schools[i] = {
'id': schoolsObject[property]['id'],
'name' : schoolsObject[property]['name'],
'location': schoolsObject[property]['location'],
};
}
}
}
console.log(schools)
Obviously this one is not what I'm after as it leaves me with Object {0: Object, 1: Object}.
Is what I want to do here possible or am I looking at it the wrong way?
Given Object:
schoolsObject = [{
"college_1":{
"id":"college_1",
"location":"Victoria",
"name":"College One"
},
"college_2":{
"id":"college_2",
"location":"Tasmania",
"name":"College Two"
}
}];
Solution:
Object.values(schoolsObject[0]);
Result:
[{
"id":"college_1",
"location":"Victoria",
"name":"College One"
},{
"id":"college_2",
"location":"Tasmania",
"name":"College Two"
}]
(Codewise) simplest solution could be using a combination of Object.keys() and Array.map():
flatSchoolsObject = Object.keys( schoolsObject[0] )
.map( ( key ) => schoolsObject[0][ key ] );
If the schoolsObject array has more entries, the code would have to be slightly adjusted:
let step1 = schoolsObject.map( ( el ) => {
return Object.keys( schoolsObject[0] )
.map( ( key ) => schoolsObject[0][ key ] );
})
flatSchoolsObject = [].concat.apply( [], step1 );
(the step1 variable is just introduced for readability reasons.)
You need to concat the result of extracting values from each item in schoolObject
flatSchoolsObject = [].concat.call(
schoolsObject.map(function(item) {
return Object.keys(item).map(function(key) {
return item[key];
})
})
)
or using Array.prototype.reduce
flatSchoolsObject = schoolsObject.reduce(function(acc, item) {
return acc.concat(Object.keys(item).map(function(key){
return item[key]
})
}, [])
You can use Array#map on the result of Object.keys to do it. Since you have just a single object in the array, we do it like this:
schoolsObject = Object.keys(schoolsObject[0]).map(function(key) {
return schoolsObject[0][key];
});
Live example:
var schoolsObject = [
{
"college_1": {
"id": "college_1",
"location": "Victoria",
"name": "College One"
},
"college_2": {
"id": "college_2",
"location": "Tasmania",
"name": "College Two"
}
}];
schoolsObject = Object.keys(schoolsObject[0]).map(function(key) {
return schoolsObject[0][key];
});
console.log(schoolsObject);
With ES2015+ you could use an arrow function to make that shorter:
schoolsObject = Object.keys(schoolsObject[0]).map(key => schoolsObject[0][key]);
// Code goes here
var schoolsObject = [{
"college_1":
{
"id":"college_1",
"location":"Victoria",
"name":"College One"
},
"college_2":
{
"id":"college_2",
"location":"Tasmania",
"name":"College Two"
}
}];
var result = Object.keys(schoolsObject[0]).map(function(key){
return schoolsObject[0][key];
})
console.log(result);
other version
var schoolsObject = [{
"college_1": {
"id": "college_1",
"location": "Victoria",
"name": "College One"
},
"college_2": {
"id": "college_2",
"location": "Tasmania",
"name": "College Two"
}
}];
var result = [];
for (var property in schoolsObject[0]) {
if (schoolsObject[0].hasOwnProperty(property)) {
result.push(schoolsObject[0][property]);
}
}
console.log(result);

Categories