1

I need to convert object:

{
        middleName: null,
        name: "Test Name",
        university: {
            country: {
                code: "PL"
            },
            isGraduated: true,
            speciality: "Computer Science"
        }
    }

to array:

[{
        key: "name",
        propertyValue: "Test Name",
    },
    {
        key: "middleName",
        propertyValue: null,
    },
    {   
        key: "university.isGraduated",
        propertyValue: true,
    },
    {   
        key: "university.speciality",
        propertyValue: "Computer Science", 
    },
    {   
        key: "university.country.code",
        propertyValue: "PL"
    }];

I wrote algorithm, but it's pretty dummy, how can I improve it? Important, if object has nested object than I need to write nested object via dot (e.g university.contry: "value")

let arr = [];
    Object.keys(parsedObj).map((key) => {
        if (parsedObj[key] instanceof Object) {
            Object.keys(parsedObj[key]).map((keyNested) => {
                if (parsedObj[key][keyNested] instanceof Object) {
                    Object.keys(parsedObj[key][keyNested]).map((keyNestedNested) => {
                        arr.push({ 'key': key + '.' + keyNested + '.' + keyNestedNested, 'propertyValue': parsedObj[key][keyNested][keyNestedNested] })
                    })
                } else {
                    arr.push({ 'key': key + '.' + keyNested, 'propertyValue': parsedObj[key][keyNested] })
                }
            })
        } else {
            arr.push({ 'key': key, 'propertyValue': parsedObj[key] })
        }
    });

Thanks

Stasoz
  • 59
  • 2
  • 7
  • 1
    Will there ever be arrays in the original object? If so, how will you handle them? – T.J. Crowder Feb 07 '22 at 10:24
  • 1
    No, just nested properties – Stasoz Feb 07 '22 at 10:24
  • How do you handle circular objects? If you are trying to reach a value with these news keys "university.country.code", you better use something like this https://lodash.com/docs/4.17.15#get – Meddah Abdallah Feb 07 '22 at 10:27
  • Is the order significant? Because the order of the `university` is at odds with the standard order of JavaScript object properties. – T.J. Crowder Feb 07 '22 at 10:28
  • If one flat object is acceptable (instead of an array of objects with separate key and value properties), you could use [Fastest way to flatten / un-flatten nested JSON objects](https://stackoverflow.com/questions/19098797/fastest-way-to-flatten-un-flatten-nested-json-objects) – Ivar Feb 07 '22 at 10:28

4 Answers4

3

A recursive function implementation.

I have considered that your object consist of only string and object as the values. If you have more kind of data types as your values, you may have to develop on top of this function.

const myObj = {
  middleName: null,
  name: "Test Name",
  university: {
    country: {
      code: "PL"
    },
    isGraduated: true,
    speciality: "Computer Science"
  }
}
const myArr = [];

function convertObjectToArray(obj, keyPrepender) {
  Object.entries(obj).forEach(([key, propertyValue]) => {
    if (typeof propertyValue === "object" && propertyValue) {
      const updatedKey = keyPrepender ? `${keyPrepender}.${key}` : key;
      convertObjectToArray(propertyValue, updatedKey)
    } else {
      myArr.push({
        key: keyPrepender ? `${keyPrepender}.${key}` : key,
        propertyValue
      })
    }
  })
}

convertObjectToArray(myObj);
console.log(myArr);
Nitheesh
  • 19,238
  • 3
  • 22
  • 49
  • Nice! Very similar to my approach, basically using `Object.entries` instead of `for-in` and writing to a closed-over array. Great minds... :-) – T.J. Crowder Feb 07 '22 at 10:34
  • Yes as I mentioned in the description, I have only considerd String and Object values. If more data types needs to be considered, that can be added on top of this. – Nitheesh Feb 07 '22 at 10:36
  • 1
    That wasn't criticism. :-) (And you're handling more than that, you're handling `null` and numbers and such -- a good answer to the question that was asked.) – T.J. Crowder Feb 07 '22 at 10:39
0

I'd probably take a recursive approach, and I'd probably avoid unnecessary intermediary arrays (though unless the original object is massive, it doesn't matter). For instance (see comments):

function convert(obj, target = [], prefix = "") {
    // Loop through the object keys
    for (const key in obj) {
        // Only handle "own" properties
        if (Object.hasOwn(obj, key)) {
            const value = obj[key];
            // Get the full key for this property, including prefix
            const fullKey = prefix ? prefix + "." + key : key;
            if (value && typeof value === "object") {
                // It's an object...
                if (Array.isArray(value)) {
                    throw new Error(`Arrays are not valid`);
                } else {
                    // ...recurse, providing the key as the prefix
                    convert(value, target, fullKey);
                }
            } else {
                // Not an object, push it to the array
                target.push({key: fullKey, propertyValue: value});
            }
        }
    }
    // Return the result
    return target;
}

Live Example:

const original = {
    middleName: null,
    name: "Test Name",
    university: {
        country: {
            code: "PL"
        },
        isGraduated: true,
        speciality: "Computer Science"
    }
};

function convert(obj, target = [], prefix = "") {
    // Loop through the object keys
    for (const key in obj) {
        // Only handle "own" properties
        if (Object.hasOwn(obj, key)) {
            const value = obj[key];
            // Get the full key for this property, including prefix
            const fullKey = prefix ? prefix + "." + key : key;
            if (value && typeof value === "object") {
                // It's an object...
                if (Array.isArray(value)) {
                    throw new Error(`Arrays are not valid`);
                } else {
                    // ...recurse, providing the key as the prefix
                    convert(value, target, fullKey);
                }
            } else {
                // Not an object, push it to the array
                target.push({key: fullKey, propertyValue: value});
            }
        }
    }
    // Return the result
    return target;
}
const result = convert(original, []);
console.log(result);
.as-console-wrapper {
    max-height: 100% !important;
}

Note that I've assumed the order of the array entries isn't significant. The output you said you wanted is at odds with the standard order of JavaScript object properties (yes, they have an order now; no, it's not something I suggest relying on ). I've gone ahead and not worried about the order within an object.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

This is the most bulletproof I could do :D, without needing a global variable, you just take it, and us it wherever you want!

const test = {
  middleName: null,
  name: "Test Name",
  university: {
    country: {
      code: "PL"
    },
    isGraduated: true,
    speciality: "Computer Science"
  }
};


function toPropertiesByPath(inputObj) {
  let arr = [];
  let initialObj = {};

  const getKeys = (obj, parentK='') => {
    initialObj = arr.length === 0 ? obj: initialObj;
    const entries = Object.entries(obj);
    for(let i=0; i<entries.length; i++) {
      const key = entries[i][0];
      const val = entries[i][1];
      const isRootElement = initialObj.hasOwnProperty(key);
      parentK = isRootElement ? key: parentK+'.'+key;

      if(typeof val === 'object' && val!==null && !Array.isArray(val)){
        getKeys(val, parentK);
      } else {
       arr.push({ key: parentK, property: val });
      }
    }
  };

  getKeys(inputObj);
  return arr;
}

console.log(toPropertiesByPath(test));
Meddah Abdallah
  • 654
  • 1
  • 7
  • 25
0

I wrote a small version using recursive function and another for validation is an object.

let values = {
  middleName: null,
  name: "Test Name",
  university: {
    country: {
      code: "PL"
    },
    isGraduated: true,
    speciality: "Computer Science"
  }
}

function isObject(obj) {
  return obj != null && obj.constructor.name === "Object"
}

function getValues(values) {
  let arrValues = Object.keys(values).map(
    v => {
      return { key: v, value: isObject(values[v]) ? getValues(values[v]) : values[v] };

    });
  console.log(arrValues);
}

getValues(values);
Nitheesh
  • 19,238
  • 3
  • 22
  • 49
danywalls
  • 709
  • 1
  • 10
  • 27