2

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"
    }
]
4
  • Flatten pertains to arrays not objects. Ex. [1, 2, 3] flattens to 1, 2, 3. Also, an object with duplicate keys is invalid. Ex. chiKeyA2 appears twice in the first object. Commented Mar 31, 2020 at 5:47
  • @zer00ne fixed the dup key...what would you call this instead? Also, do you any help for how to solve the problem? Commented Mar 31, 2020 at 5:54
  • Looking at what you expect...the pattern looks like this: 1. Each object within an object must have their key/values moved to the parent object. 2. Then the empty object is removed. It doesn't make much sense...but if that's what you really want there's a way to do so. I'll post an answer. Commented Mar 31, 2020 at 6:03
  • Thank you for the answers all worked well, chosen answer was a little shorter! Commented Mar 31, 2020 at 6:42

4 Answers 4

3

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)))

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. this is a very simple straightforward answer. i was looking for something like this. thanks a lot
1

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

3 Comments

Is there a big difference from using Array.map() other than variable assignment?
This code working in my machine, I hope it helps you start with this and later enhance it with either map or filter
@BrettB not much the only difference is assignment will modify the original passed array whereas when you use map it will create a new array.
1

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)

Comments

0

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)) {...

  1. Declare an empty array and iterate through each object literal within the array of objects:

    let array = [];
    for (let obj of objArray) {...
    
  2. 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)) {...
    
  3. Check each value of each object literal -- if the value is an object literal...

    if (Object.prototype.toString.call(value) == "[object Object]") {...
    
  4. ...iterate through the value and assign each key/value to the empty object...

    for (let [k, v] of Object.entries(value)) {
      object[k] = v;
    }
    
  5. ...otherwise assign the key/value to the empty object...

    } else {
      object[key] = value;
    }
    
  6. Push the new object to the new array:

    array.push(object);
    

Demo

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));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.