3

I have some attributes from a nested object that is inside the parent object but I would like to merge nested object with the parent object to be flatten.

Original object:

enrollment = {
  user: {
    id: 'string',
    name: 'string'
  },
  finished: 'boolean',
  path: 'string'
}

expected flatten object:

user: {
  id: 'string',
  name: 'string',
  finished: 'boolean',
  path: 'string'
}

6 Answers 6

4

You can recursively build object any number of nested objects. So, this function is not your case dependent:

var enrollment = {
user: {
    id: 'string',
    name: 'string'
},
finished: 'boolean',
path: 'boolean'
}

var enrollment2 = {
user: {
    id: 'string',
    name: 'string'
},
test: {
    test1: {
        test2: {
            val0:'val0',
            test4: { //3rd level nested object for example
                val1: 'val1',
                val2: 'val2'
            }
        }
    }
},
finished: 'boolean',
path: 'boolean'
}

const flat = (obj, out) => {
    Object.keys(obj).forEach(key => {
        if (typeof obj[key] == 'object') {
            out = flat(obj[key], out) //recursively call for nesteds
        } else {
            out[key] = obj[key] //direct assign for values
        }

    })
    return out
}

console.log(flat(enrollment, {}))
console.log(flat(enrollment2, {}))

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

1 Comment

In the general use case - in case of null value, typeof obj[key] return 'object' and TypeError exception will be thrown in the inner recursion.
4

I needed something that avoids rewriting keys with the same name that were in different levels in the original object. So I wrote the following:

const flattenObject = (obj, parentKey = '') => {
    if (parentKey !== '') parentKey += '.';
    let flattened = {};
    Object.keys(obj).forEach((key) => {
        if (typeof obj[key] === 'object' && obj[key] !== null) {
            Object.assign(flattened, flattenObject(obj[key], parentKey + key))
        } else {
            flattened[parentKey + key] = obj[key]
        }
    })
    return flattened;
}

var test = {
    foo: 'bar',
    some: 'thing',
    father: {
        son1: 'son1 value',
        son2: {
            grandchild: 'grandchild value',
            duplicatedKey: 'note this is also used in first level',
        },
    },
    duplicatedKey: 'note this is also used inside son2',
}

let flat = flattenObject(test);
console.log(flat);

// how to access the flattened keys:
let a = flat['father.son2.grandchild'];
console.log(a);

Also checks if the object is null, as I was having some problems with that in my usage.

Comments

1

Here's a quick and dirty way to flatten your object:

var enrollment = {
    user: {
        id: 'string',
        name: 'string',
    },
    fineshed: true,
    path: false,
};

var user = Object.assign(enrollment.user);
user.fineshed = enrollment.fineshed;
user.path = enrollment.path;

For a generic method with a couple of caveats of no shared key names and only flattening 1 level of depth:

var enrollment = {
	user: {
		id: 'string',
		name: 'string',
	},
	fineshed: true,
	path: false,
};

const flatten = (object) => {
	let value = {};
	for (var property in object) {
		if (typeof object[property] === 'object') {
			for (var p in object[property]) {
				value[p] = object[property][p];
			}
		} else {
			value[property] = object[property];
		}
	}

	return value;
};

let user = flatten(enrollment);

console.log(user);

Comments

1

using recursion and reduce.

note that if value itself is an array containing objects, you might want add another check like !Array.isArray(value) depending on your case

function flatObj(obj) {
  return Object.entries(obj).reduce(
    (flatted, [key, value]) =>
      typeof value == "object"
        ? { ...flatted, ...flatObj(value) }
        : { ...flatted, [key]: value },
    {}
  );
}

Comments

0

Just want a single Object:

const enrollment = {
  user: {
    id: 'string',
    name: 'string'
  },
  finished: 'boolean',
  path: 'boolean'
}
function propsToUser(enrollObj){
  const u = {...enrollObj.user};
  for(let i in enrollObj){
    if(i !== 'user')u[i] = enrollObj[i];
  }
  return u;
}
const user = propsToUser(enrollment);
console.log(user);

Comments

0

Below code snippet takes nested input object like this :

{
        name:'Namig',
        surname:'Hajiyev',
        address:{
            city:'Sumgait',
            country:'Azerbaijan',
            geo: {
                lat:'40.5897200',
                long:'49.6686100'
            }
        }
    }

and returns result flattened object like this:

{
  "name": "Namig",
  "surname": "Hajiyev",
  "address.city": "Sumgait",
  "address.country": "Azerbaijan",
  "address.geo.lat": "40.5897200",
  "address.geo.long": "49.6686100"
}

Here is my code :

function flattenObject(obj, newObj, prefix) {
    newObj = newObj || {};
    prefix = prefix || "";
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            const type = typeof obj[key];
            const newKey = !!prefix ? prefix + "." + key : key;
            if (type === "string") {
                newObj[newKey] = obj[key];
            }
            else if (type === "object") {
                flattenObject(obj[key], newObj, newKey);
            }
        }
    }
    return newObj;
}

var obj = {
    name:'Namig',
    surname:'Hajiyev',
    address:{
        city:'Sumgait',
        country:'Azerbaijan',
        geo: {
            lat:'40.5897200',
            long:'49.6686100'
        }
    }
}

console.log(flattenObject(obj));

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.