Reputation: 53
I'm trying to write a function that will accept a nested object array, and dynamically return the flattened result. arrayProperties.filter()
is not returning an array of objects like I expect.
const data = [
{
parKeyA: "parValA",
parKeyA1:
{chiKeyA1: "chiValA1", chiKeyA2: "chiValA2"},
parKeyA2: {chiKeyA3: "chiValA3"}
},
{
parKeyB: "parValB",
parKeyB1:
{chiKeyB1:"chiValB1"}
}
]
flatData = flatNestedObjArray(data);
console.log(flatData);
function flatNestedObjArray(array) {
let flatArray = array.map(element => {
let arrayProperties = Object.entries(element);
//filter not returning array of objects
let nestedObjects = arrayProperties.filter(property => {
const parentValue = property[1];
if (typeof parentValue === "object" && parentValue !== null) {
return parentValue;
}
});
//nestedObjects should be array of objects
let merged = nestedObjects.map(obj => element.concat(obj));
return merged;
});
return flatArray;
}
Expected Result:
const data = [
{
parKeyA: "parValA",
chiKeyA1: "chiValA1",
chiKeyA2: "chiValA2",
chiKeyA2: "chiValA2"
},
{
parKeyB: "parValB",
chiKeyB1:"chiValB1"
}
]
Upvotes: 2
Views: 3033
Reputation: 43880
Object.entries()
takes an object and converts it into a two-dimensional array:
let object = {keyA: "valueA", keyB: "valueB", keyC: {kA: "vA", kB: "vB"}};
let array = Object.entries(object);
// array = [["keyA", "valueA"], ["keyB", "valueB"], ["keyC", {kA: "vA", kB: "vB"}]];
Using the above within a for...of
loop, each entry can be destructured:
for (let [key, value] of Object.entries(object)) {...
Declare an empty array and iterate through each object literal within the array of objects:
let array = [];
for (let obj of objArray) {...
On each object, declare an empty object and then convert each key/value of each object into a sub-array:
let object = {};
for (let [key, value] of Object.entries(obj)) {...
Check each value of each object literal -- if the value is an object literal...
if (Object.prototype.toString.call(value) == "[object Object]") {...
...iterate through the value and assign each key/value to the empty object...
for (let [k, v] of Object.entries(value)) {
object[k] = v;
}
...otherwise assign the key/value to the empty object...
} else {
object[key] = value;
}
Push the new object to the new array:
array.push(object);
const data = [{
parKeyA: "parValA",
parKeyA1: {
chiKeyA1: "chiValA1",
chiKeyA2: "chiValA2"
},
parKeyA2: {
chiKeyA3: "chiValA3"
}
},
{
parKeyB: "parValB",
parKeyB1: {
chiKeyB1: "chiValB1"
}
}
];
function subObjToKeyVal(objArr) {
let array = [];
for (let obj of objArr) {
let object = {};
for (let [key, value] of Object.entries(obj)) {
if (Object.prototype.toString.call(value) == "[object Object]") {
for (let [k, v] of Object.entries(value)) {
object[k] = v;
}
} else {
object[key] = value;
}
}
array.push(object);
}
return array;
}
console.log(subObjToKeyVal(data));
Upvotes: 0
Reputation: 50291
You can use map
which will return a array and a recursive function. Have added comment in the code , hopefully that will be useful
const data = [{
parKeyA: "parValA",
parKeyA1: {
chiKeyA1: "chiValA1",
chiKeyA2: "chiValA2"
},
parKeyA2: {
chiKeyA3: "chiValA2"
}
},
{
parKeyB: "parValB",
parKeyB1: {
chiKeyB1: "chiValB1"
}
}
]
/* Recursive function.It will take a object,iterate the object and check if the value of the key is another object. If it is another object then call same recursive function */
function getFlatObj(obj) {
let newObject = {}
function doRecurssion(currObj) {
// iterate through the object
for (let keys in currObj) {
// check if the value is another object
if (typeof currObj[keys] === 'object' && typeof currObj[keys] !== null) {
doRecurssion(currObj)
} else {
// if not another object then add key and value
newObject[keys] = currObj[keys]
}
}
return newObject;
}
return doRecurssion(obj);
}
let flatObj = data.map((item) => {
const acc = {};
for (let keys in item) {
if (typeof item[keys] === 'object' && typeof item[keys] !== null) {
Object.assign(acc, getFlatObj(item[keys]))
} else {
acc[keys] = item[keys]
}
}
return acc;
}, {});
console.log(flatObj)
Upvotes: 1
Reputation: 37755
You can use recursion to flatten the objects into a single level object and pass that function to map to get an array of flattened object
const data = [{
parKeyA: "parValA",
parKeyA1: {
chiKeyA1: "chiValA1",
chiKeyA2: "chiValA2"
},
parKeyA2: {
chiKeyA3: "chiValA3"
}
},
{
parKeyB: "parValB",
parKeyB1: {
chiKeyB1: "chiValB1",
chiKeyB2: {}
}
}
]
let flatten = (obj, final = {}) => {
for (let key in obj) {
if (typeof obj[key] === 'object' && obj[key] != null) {
flatten(obj[key], final)
} else {
final[key] = obj[key]
}
}
return final
}
console.log(data.map((v) => flatten(v)))
Upvotes: 3
Reputation: 4054
You can use object property loop using in
keyword for each level using recursion
for(var prop in data) {
....
}
I used an old recursion technique to start with a working code
function flatten(data) {
var newData = {};
for(var prop in data) {
if(typeof data[prop] == "object") {
var childs = flatten(data[prop])
for(var cprop in childs){
newData[cprop] = childs[cprop];
}
}else {
newData[prop] = data[prop]
}
}
return newData;
}
for(var i=0;i<data.length;i++)
data[i] = flatten(data[i]);
console.log(data);
You need to handle duplicates
Upvotes: 1