Convert object with one property into parent property - javascript

I have converted javascript object from xml, this is example of object:
{
name: 'current name',
attr1: 'attribute1',
attr2: 'attribute2',
address: {
name: 'name1',
value: {
value: '12'
},
attr3: {
name: 'no name',
attr4: {
attr4: 'attribute4'
}
}
},
price: {
price: '500'
},
in_house: {
in_house: '2'
}
}
how I can convert into this:
{
name: 'current name',
attr1: 'attr1',
address:{
name: 'name1',
value: '12',
attr3: {
name: 'no name',
attr4: 'attribute3'
}
}
attr2: 'attr2',
price: 500,
in_house: 2
}
need convert all unusefull object into property, example
{
price :
price: '500'
}
into
{ price: '500'}

You could use an iterative, recursive approach for the keys and their values.
function moveUp(object, last) {
var keys = Object.keys(object);
if (keys.length === 1 && keys[0] in last) {
last[keys[0]] = object[keys[0]];
if (last[keys[0]] !== null && typeof last[keys[0]] === 'object') {
moveUp(last[keys[0]], last);
}
return;
}
keys.forEach(function (k) {
if (object[k] !== null && typeof object[k] === 'object') {
moveUp(object[k], object)
}
});
}
var object = { name: 'current name', attr1: 'attribute1', attr2: 'attribute2', address: { name: 'name1', value: { value: '12' }, attr3: { name: 'no name', attr4: { attr4: 'attribute4' } } }, price: { price: '500' }, in_house: { in_house: '2' }, test: { test: { test: { banane: 42 } } } };
moveUp(object);
console.log(object);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Here is a recursive function that will iterate over the root object and pass over every node in it to see if the current node has an immediate child of the same name.
const obj = { name: 'current name', attr1: 'attribute1', attr2: 'attribute2',
address: { name: 'name1', value: { value: '12' }, attr3: { name: 'no name', attr4: { attr4: 'attribute4' }}}, price: { price: '500' }, in_house: { in_house: '2' }}
// helper function to check if a value is an object
const isObject = thing => (
typeof thing !== 'undefined' &&
typeof thing.constructor &&
thing.constructor === Object
)
const mutateUselessProperties = (root) => {
// we need to recursively go through the root object and return it's result
// after removing properties so we create an inner function for recursion
const go = (obj) => {
// if it's just a value return it
if (!isObject(obj)){
return obj
}
// it's an object so we loop over the keys
for (let key in obj) {
// check if it's an object with a child of the same key
if (isObject(obj[key]) && obj[key][key]) {
// reassign the property to it's child of the same name
obj[key] = obj[key][key]
}
// check if it's still an object after possible reassignment
if (isObject(obj[key])) {
// it's an object so recrusively go through the child properties
obj[key] = go(obj[key])
}
// may as well check if we are dealing with an array at the same time
if (Array.isArray(obj[key])) {
obj[key] = obj[key].map(go)
}
}
// return the current iteration
return obj
}
// run the recursive iteration
go(root)
// return the root object that has been mutated
return root
}
console.log(mutateUselessProperties(obj))

If the nested single properties all have the same name with the parent property then the following should work;
var obj = {
name: 'current name',
attr1: 'attribute1',
attr2: 'attribute2',
address: {
name: 'name1',
value: {
value: '12'
},
attr3: {
name: 'no name',
attr4: {
attr4: 'attribute4'
}
}
},
price: {
price: '500'
},
in_house: {
in_house: '2'
}
};
for (var prop in obj) typeof obj[prop] === "object" && Object.keys(obj[prop]).length === 1 && (obj[prop] = obj[prop][prop]);
console.log(obj);

Related

Javascript - Remove object from nested array

I have array of objects, each object must have key and title, but children is optional, and it can be nested, i can have children inside of children many times. I want to remove some object by provided key value (for example key 677). I tried with filter but i only remove first level. Also have tried recursion, but not sure if i did it right.
const data = [{
key: '1',
title: 'title 1',
children: [{
key: '098',
title: 'hey',
children: [{
key: '677',
title: 'child'
}]
}]
},
{
key: '123',
title: 'tile 111'
},
{
key: '345',
title: 'something'
}
];
const rem = '677';
const del = (el) => {
if (!el.children) {
return el.key !== rem;
} else {
if (el.key !== rem) {
del(el.children);
return el;
}
}
};
const res = data.filter((el) => {
return del(el);
});
console.log(res);
I guess your existing solution is like
const data = [
{
key: '1',
title: 'title 1',
children: [{
key: '098',
title: 'hey',
children: [{ key: '677', title: 'child'}]
}]
},
{ key: '123', title: 'tile 111' },
{ key: '345', title: 'something' }
];
function removeByKey(arr, removingKey){
return arr.filter( a => a.key !== removingKey);
}
So it works on the first level but not deeply.
Just change it like that will do the jobs
function removeByKey(arr, removingKey){
return arr.filter( a => a.key !== removingKey).map( e => {
return { ...e, children: removeByKey(e.children || [], removingKey)}
});
}
Little warning, children property will not be set to [] for every item not having any children.
So how it works? Well instead of keeping acceptable items as they are, we make a copy using {...e} that's equivalent to {key:e.key, title:e.title, children:e.children} in this case.
We know force to override the property children with removeByKey(e.children || [], removingKey), so we call the method recursively. Not the function works deeeply.
I would use a recursion approach with findIndex and splice. Using some will allow the code to exit without running through the entire tree.
const data = [{
key: '1',
title: 'title 1',
children: [{
key: '098',
title: 'hey',
children: [{
key: '677',
title: 'child'
}]
}]
},
{
key: '123',
title: 'tile 111'
},
{
key: '345',
title: 'something'
}
];
const removeKey = (data, key) => {
// look to see if object exists
const index = data.findIndex(x => x.key === key);
if (index > -1) {
data.splice(index, 1); // remove the object
return true
} else {
// loop over the indexes of the array until we find one with the key
return data.some(x => {
if (x.children) {
return removeKey(x.children, key);
} else {
return false;
}
})
}
}
console.log(removeKey(data, '677'))
console.log(JSON.stringify(data));
You can use some simple recursion to do the trick:
const data = [
{
key: '1',
title: 'title 1',
children: [
{
key: '098',
title: 'hey',
children: [{ key: '677', title: 'child'}]
}
]
},
{ key: '123', title: 'tile 111' },
{ key: '345', title: 'something' }
];
function removeByKey(key, arr) {
// loop through all items of array
for(let i = 0; i < arr.length; i++) {
// if array item has said key, then remove it
if(arr[i].key === key) {
arr.splice(i, 1);
} else if(typeof(arr[i].children) !== "undefined") {
// if object doesn't have desired key but has children, call this function
// on the children array
removeByKey(key, arr[i].children);
}
}
}
removeByKey('098', data);
console.log(data);
This may be a little easier to understand than the other answer provided.

Extract parameters from object

I have next object:
const types = {
sometypes: {
TYPE1: { name: 'type1', value: '1' },
TYPE2: { name: 'type2', value: '2' },
TYPE3: { name: 'type3', value: '3' },
},
TYPE4: { name: 'type4' },
};
how can I extract all name fields?
Expected result: ['type1','type2','type3','type4']
You can create a recursive function to loop through the object.
const types = {
sometypes: {
TYPE1: {
name: 'type1',
value: '1'
},
TYPE2: {
name: 'type2',
value: '2'
},
TYPE3: {
name: 'type3',
value: '3'
},
},
TYPE4: {
name: 'type4'
},
};
function extractNames(obj) {
let result = [];
Object.keys(obj).forEach(k => {
if (k == 'name') {
result.push(obj[k]);
} else if (typeof obj[k] == 'object') {
result.push(...extractNames(obj[k]));
}
});
return result;
}
console.log(extractNames(types));
Take entries of object and then map it accordingly.(I'm assuming your object is not nested)
var types = { sometypes: { TYPE1: { name: 'type1', value: '1' }, TYPE2: { name: 'type2', value: '2' }, TYPE3: { name: 'type3', value: '3' }, }, TYPE4: { name: 'type4' },};
var result = Object.entries(types).flatMap(([k,v])=> v.name ? v.name : Object.values(v).map(({name})=>name));
console.log(result);
This getNames function does it recursively.
const types = getSourceObject();
function getNames(obj, names){
const keys = Object.keys(obj);
keys.forEach( (key) => {
if(obj[key].name){ names.push(obj[key].name); }
else{ getNames(obj[key], names); }
});
}
const namesArr = [];
getNames(types, namesArr);
console.log(namesArr);
function getSourceObject(){
return {
sometypes: {
TYPE1: { name: 'type1', value: '1' },
TYPE2: { name: 'type2', value: '2' },
TYPE3: { name: 'type3', value: '3' }
},
TYPE4: { name: 'type4' }
};
}

Filter nested object from parent object

I have a parent object with a child array of objects nest underneath. Each object contains an id key with a unique value. A filter function needs to search the parent object for an id, if it does not equal the given id then recursively search through nested objects for the id until it is found. Once the object with the given key is found the remove and return the updated myObject.
The structure looks as followed:
let myObject = {
key: 1,
name: 'hello',
children: [
{
key: 2,
name: 'world',
children: []
},
{
key: 3,
name: 'hope',
children: [
{
key: 4,
name: 'you',
children: [{
key: 5,
name: 'are',
children: []
}]
},
{
key: 6,
name: 'having',
children: [{
key: 7,
name: 'fun',
children: []
}]
}
]
}
]
}
let given = 4;
if (myObject.key !== given) {
myObject = searchChild(myObject, given)
} else {
myObject = {}
}
function searchChild(parent, given) {
parent.children.map(child => {
return child.children.filter(item => {
if (item.key === given) return item;
else if (item.key !== given
&& child.children.length > 0
&& child.children != undefined) {
searchChild(child.children, given);
}
})
})
}
Currently, I am receiving a type error when running the recursive function.
The output should look like where the keys are updated to the new order in tree:
{
key: 1,
name: 'hello',
children: [
{
key: 2,
name: 'world',
children: []
},
{
key: 3,
name: 'hope',
children: [
{
key: 4,
name: 'having',
children: [{
key: 5,
name: 'fun',
children: []
}]
}
]
}
]
}
Here is function you can call for your object
function searchInChild(parent,key){
parent.children = parent.children.filter((c)=>{
if(key == c.key ){
result = c;
return false;
}
return true;
});
if(result == null){
for(c in parent.children){
searchInChild(parent.children[c],key);
}
}
}
Where, you can simply pass searchInChild(myObject,key) & make result global variable.
You pass child.children but you have to pass child you already iterate through children in the function.
let myObject = {
key: 1,
name: 'hello',
children: [
{
key: 2,
name: 'world',
children: []
},
{
key: 3,
name: 'hope',
children: [
{
key: 4,
name: 'you',
children: [{
key: 5,
name: 'are',
children: []
}]
},
{
key: 6,
name: 'having',
children: [{
key: 7,
name: 'fun',
children: []
}]
}
]
}
]
}
let given = 4;
if (myObject.key !== given) {
myObject = searchChild(myObject, given)
} else {
myObject = {}
}
function searchChild(parent, given) {
if(parent && parent.children) {
parent.children.map(child => {
return child.children.filter(item => {
if (item.key === given) return item;
else if (item.key !== given
&& child.children.length > 0
&& child.children != undefined) {
searchChild(child, given);
}
})
})
}
}

How to Iterate through an array object inside another array object (JSON)?

The following is a list of users I receive from an API call that gets the list of users from AWS cognito. I want to be able to iterate through it to display the name and email of the user on a web page. I am trying result[0].attributes[3] to iterate to "given_name", result being the object.
You can use filter to determine if an object property can be found, and then return that object.
result[0].Attributes.filter(obj => obj.name === name);
Here's an example:
let result = [{
Attributes: [{
name: "Mario"
},
{
name: "Luigi"
},
{
name: "Toad"
},
{
name: "Peach"
}
]
}]
function lookfor(name) {
return result[0].Attributes.filter(obj => obj.name === name);
}
console.log(lookfor("Mario"));
console.log(lookfor("Peach"));
for(var i in array){
var attr = array[i].Attributes;
for(var l in attr){
// attr[l].Name returns name
// attr[l].Value returns values
}
}
You can iterate an array using map
arrributes.map(function(arr) => {
console.log(arr.Name, arr.Value)
})
const response = [
{ Attributes: [
{Name: 'given_name', Value: 'name 1'},
{Name: 'family_name', Value: 'family 1'},
{Name: 'email', Value: 'email1#gmail.com'}
]
},
{ Attributes: [
{Name: 'given_name', Value: 'name 2'},
{Name: 'family_name', Value: 'family 2'},
{Name: 'email', Value: 'email2#gmail.com'}
]
},
];
const users = response.map((ele) => {
const { Attributes } = ele;
return Attributes.reduce((agg, {Name, Value}) => {
if (Name === 'given_name') {
agg.name = Value;
}
if (Name === 'email') {
agg.email = Value;
}
return agg;
}, {});
});
console.log(users);
Object.keys(result).forEach(key => {
let resultObject = result[key].map(array => {
if (array.Name == "given_name") {
console.log(array.value)
} else if (array.Name == "email") {
console.log(array.value);
}
});
});

How to turn dot notation string into an object in Javascript

I'm trying to turn a dot notation string into an object, for example given
[{
key: 'app.team.instance',
value: 'some value1'
}, {
key: 'app.team.instance.obj',
value: 'some value'
}, {
key: 'app.team.app.some',
value: 'some value'
}, {
key: 'app.service.awesome.more',
value: 'more values'
}]
I would like to turn it an object like to get
{
"team": {
"instance": "some value1",
"server": {
"obj": "some value"
},
"app": {
"some": "some value"
}
},
"service": {
"awesome": {
"more": "more values"
}
}
}
This's what I have tried using the following function. Looking at my function what have I missed or should improve?
function createObjFromRows(skip, key, value, obj) {
const ARRAY_KEYS = key.split('.');
const ARRAY_LENGTH = ARRAY_KEYS.length;
let i = skip ? 1 : 0;
for (; i < ARRAY_LENGTH; i++) {
if (i < (ARRAY_LENGTH - 1)) {
if (!obj.hasOwnProperty(ARRAY_KEYS[i])) { obj[ARRAY_KEYS[i]] = {}; }
} else {
obj[ARRAY_KEYS[i - 1]][ARRAY_KEYS[i]] = value;
}
}
}
This's what I get currently.
{
team: {
instance: 'some value1'
},
server: {
obj: 'some value'
},
app: {
some: 'some value'
},
service: {},
awesome: {
more: 'more values'
}
}
You can use array.prototype.reduce :
var datas = [ {key: 'app.team.instance', value: 'some value1'}, {key: 'app.team.server.obj', value: 'some value'}, {key: 'app.team.app.some',value: 'some value'}, {key: 'app.service.awesome.more', value: 'more values'}];
var res = datas.reduce((m, o) => {
var keys = o.key.split('.');
var cur = m;
keys.forEach((key, i) => {
if (i < keys.length - 1) {
cur[key] = cur[key] || {};
cur = cur[key];
} else {
cur[key] = o.value;
}
});
return m;
}, {});
console.log(res);
You could split the given key strings and save the last key for the assignment of the value after iterating the keys to the nested property.
var data = [{ key: 'app.team.instance', value: 'some value1' }, { key: 'app.team.server.obj', value: 'some value' }, { key: 'app.team.app.some', value: 'some value' }, { key: 'app.service.awesome.more', value: 'more values' }],
result = data.reduce(function (r, o) {
var path = o.key.split('.'),
last = path.pop();
path.reduce(function (p, k) {
return p[k] = p[k] || {};
}, r)[last] = o.value;
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources