Change value from an array - javascript

I have the next code:
const arr = [
{
name:'john',
cars:[
{audi:1},
{bmw:2}
]
},
{
name:'bill',
cars:[
{audi:10},
{bmw:0}
]
}
]
const arr1 = arr.map(i => {
if(i.name === 'john') {
return i.cars.map( a => {
return {
...i,
test:[2]
}
})
}
return i
})
console.log(arr1)
Here i want too loop through the array and for the first object to change the cars array, adding test:[2]. For this i used:
const arr1 = arr.map(i => {
if(i.name === 'john') {
return i.cars.map( a => {
return {
...i,
test:[2]
}
})
}
return i
})
The issue is that my code don't return what i want. I get the first object like:
0: Object
name: "john"
cars: Array[2]
test: 2
1: Object
name: "john"
cars: Array[2]
test: 2
but i need like this:
{
name:'john',
cars:[
{
audi:1,
test: [2],
},
{bmw:2}
]
},
How to solve my issue?

Since you only want to change the first item in the cars array, I don't think map is right - instead, just list the first changed car as an object literal inside an array, then spread the remaining cars into the array with .slice(1):
const arr = [
{
name:'john',
cars:[
{audi:1},
{bmw:2}
]
},
{
name:'bill',
cars:[
{audi:10},
{bmw:0}
]
}
]
const arr1 = arr.map(person => (
person.name !== 'john'
? person
: ({
name: person.name,
cars: [
{ ...person.cars[0], test: [2] },
...person.cars.slice(1)
]
})
));
console.log(arr1)

You could address the right position and add the wanted property.
const
data = [{ name: 'john', cars: [{ audi: 1 }, { bmw: 2 }] }, { name: 'bill', cars: [{ audi: 10 }, { bmw: 0 }] }],
add = { target: [0, 0], value: { test: [2] } }
result = data.map((o, i) => i === add.target[0]
? { ...o, cars: o.cars.map((p, j) => j === add.target[1]
? {... p, ...add.value }
: p)
}
: o);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Given the desired result, a non mapping solution may be viable?
const arr = [{
name: 'john',
cars: [{
audi: 1
},
{
bmw: 2
}
]
},
{
name: 'bill',
cars: [{
audi: 10
},
{
bmw: 0
}
]
}
];
// clone the initial arr
const arrModified = Object.assign([], arr);
// find John
const indexJohn = arrModified.findIndex(v => v.name === "john");
if (indexJohn > -1) {
// modify the desired value
arrModified[indexJohn].cars[0].test = [2];
}
console.log(arrModified[0].cars);
.as-console-wrapper { top: 0; max-height: 100% !important; }

Related

How to merge object with jquery by id

I need to be able to concatenate two JavaScript objects like the following:
let arr1 = [
{"0": { id: "abdc4051", date: "2017-01-24" }},
{"1": { id: "abdc4052", date: "2017-01-22" }}
];
let arr2 = [
{"0": { category: "Sport", data: {code: "abdc4051", name: "ab"} } },
{"1": { category: "Others", data: {code: "abdc4052", name: "abc"} } }
];
Does anyone have a script for this or know of a built in way to do this?
I want the date to be added in the data on arr2 with the condition code equal to id
Your object shape makes this harder than it should be. Are you certain you want the sequential properties in each object, or is that an artifact of logging/poor parsing?
You'll need to work around them if you actually need them, in the snippet below using Object.values() in creating a Map from arr1, and using Object.entries() in the final map() call on arr2 to store the sequential key and then reintroduce it in the return after the merge logic.
const
arr1 = [{ "0": { id: "abdc4051", date: "2017-01-24" } }, { "1": { id: "abdc4052", date: "2017-01-22" } }],
arr2 = [{ "0": { category: "Sport", data: { code: "abdc4051", name: "ab" } } }, { "1": { category: "Others", data: { code: "abdc4052", name: "abc" } } }],
// create map of dates: Map(2) { 'abdc4051' => '2017-01-24', 'abdc4052' => '2017-01-22' }
dateMap = new Map(arr1.map(o => {
const [{ id, date }] = Object.values(o);
return [id, date];
})),
// map over arr2, get date from Map and add it to 'data' if it exists
result = arr2.map(o => {
const [[k, _o]] = Object.entries(o);
const date = dateMap.get(_o.data.code);
return {
[k]: {
..._o,
data: { ..._o.data, ...(date ? { date } : {}) }
}
};
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you don't need the initial sequential keys the merge becomes much less verbose.
const
arr1 = [{ id: "abdc4051", date: "2017-01-24" }, { id: "abdc4052", date: "2017-01-22" }],
arr2 = [{ category: "Sport", data: { code: "abdc4051", name: "ab" } }, { category: "Others", data: { code: "abdc4052", name: "abc" } }],
dateMap = new Map(arr1.map(o => [o.id, o.date])),
result = arr2.map(o => (
{
...o,
data: { ...o.data, ...(dateMap.has(o.data.code) ? { date: dateMap.get(o.data.code) } : {}) }
}
));
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to change the nested array object to object depending on type in javascript

I would like to know how to change nested array object to object depending on key in javascript
I have objects obj1 and obj2, depending on key item type change the object.
function changeObj(obj){
let result = obj.reduce(function (acc, item) {
if(item.items.trim() !== "" && item.key.trim() !== ""){
acc[item.key] = item.items
return acc
}
return acc
}, {});
return result;
}
let result = this.changeObj(obj2)
var obj1 = [
{ id:0, items:["SG","AU"], count: 2, key:"countries"},
{ id:1, items:["finance"], count: 3 key:"info"}
]
var obj2 = [
{ id:0, items: "SG", key: "country"},
{ id:1, items: "details", key: "info"}
]
Expected Output:
// if items key is array
{
fields: {
countries: ["SG","AU",2],
info: ["finance",3]
}
}
//if items key is string
{
fields: {
country: "SG",
info: "details"
}
}
I think the reason your code is not running is because the wrong format of your objects (1 and 2). Your code is okay except the condition because trim() only works on string type so it errors on array. Try this code snippet
function changeObj(obj){
let result = obj.reduce(function (acc, item) {
acc[item.key] = item.items;
return acc;
}, {});
return result;
}
var obj1 = [
{ id:0, items:["SG","AU"], count: 2, key:"countries"},
{ id:1, items:["finance"], count: 3, key:"info"}
]
var obj2 = [
{ id:0, items: "SG", key: "country"},
{ id:1, items: "details", key: "info"}
]
console.log(changeObj(obj1));
const changeObj = obj =>
obj.reduce((acc, item) => {
if (Array.isArray(item.items)) {
acc[item.key] = [...item.items, item.count];
} else {
acc[item.key] = item.items;
}
return acc;
}, {});
var obj1 = [
{ id: 0, items: ['SG', 'AU'], count: 2, key: 'countries' },
{ id: 1, items: ['finance'], count: 3, key: 'info' }
];
var obj2 = [
{ id: 0, items: 'SG', key: 'country' },
{ id: 1, items: 'details', key: 'info' }
];
console.log(changeObj(obj1));
console.log(changeObj(obj2));
or cleaned up even more
const changeObj = obj =>
obj.reduce((acc, { items, key, count }) => {
Array.isArray(items) ? (acc[key] = [...items, count]) : (acc[key] = items);
return acc;
}, {});
var obj1 = [
{ id: 0, items: ['SG', 'AU'], count: 2, key: 'countries' },
{ id: 1, items: ['finance'], count: 3, key: 'info' }
];
var obj2 = [
{ id: 0, items: 'SG', key: 'country' },
{ id: 1, items: 'details', key: 'info' }
];
console.log(changeObj(obj1));
console.log(changeObj(obj2));

React How to add new dynamic key to existing state?

I have getting the data from database as an array.
So now I'm getting array like this:
orders:[
{
_id:1,
name: honda,
}
{
_id:2,
name: suzuki,
}
{
_id:3,
name: audi,
}
]
So my question is how can I attach new key value to the array, so It needs to look like this:
orders:[
{
_id:1,
name: honda,
opened:true,
}
{
_id:2,
name: suzuki,
opened:true,
}
{
_id:3,
name: audi,
opened:true,
}
]
For now I'm trying with this code, but this doesn't work:
getOrders(orders).then(response => {
response.map(itm=>{
const ordersData=[...itm]
const opened={opened:true}
this.setState({
openedOrders: [ordersData,opened]
})
})
})
openedOrders is new state object that I create.
What is best solution for this?
Thanks
Your map should look like this. (Note the return statement in map function)
orders.map(item=> {
return {...item, opened:true}
})
So your function could look like
getOrders(orders).then(response => {
let openedOrders = orders.map(item=> {
return {...item, opened:true}
})
this.setState({
openedOrders
})
})
Assuming response contains the first array in your OP:
getOrders(orders).then(response => {
const openedOrders = response.map(order => ({ ...order, open: true}))
this.setState({ openedOrders } )
})
response.map(order => ({ ...order, open: true}) adds a key open with the value true to every order in the array.
To add dynamic keys to a object in javascript we use [].
var x = [{ _id : 1, name: Suzuki}];
x[0]['opened'] = true;
console.log(x);
// [{ _id : 1, name: Suzuki, opened: true}];
Use foreach() to loop through all the orders in the array and add the desired property for each order.
let orders = [{
_id: 1,
name: 'honda',
}, {
_id: 2,
name: 'suzuki',
}, {
_id: 3,
name: 'audi',
}]
orders.forEach(o => o.opened = true)
console.log(orders)
You could add a new property to the objects.
var orders = [{ _id: 1, name: 'honda' }, { _id: 2, name: 'suzuki' }, { _id: 3, name: 'audi' }],
additionalProp = { opened: true };
orders.forEach(o => Object.assign(o, additionalProp));
console.log(orders);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Or map a new array without mutating the original objects.
var orders = [{ _id: 1, name: 'honda' }, { _id: 2, name: 'suzuki' }, { _id: 3, name: 'audi' }],
additionalProp = { opened: true },
result = orders.map(o => Object.assign({}, o, additionalProp));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to find a object in a nested array using recursion in JS

Consider the following deeply nested array:
const array = [
{
id: 1,
name: "bla",
children: [
{
id: 23,
name: "bla",
children: [{ id: 88, name: "bla" }, { id: 99, name: "bla" }]
},
{ id: 43, name: "bla" },
{
id: 45,
name: "bla",
children: [{ id: 43, name: "bla" }, { id: 46, name: "bla" }]
}
]
},
{
id: 12,
name: "bla",
children: [
{
id: 232,
name: "bla",
children: [{ id: 848, name: "bla" }, { id: 959, name: "bla" }]
},
{ id: 433, name: "bla" },
{
id: 445,
name: "bla",
children: [
{ id: 443, name: "bla" },
{
id: 456,
name: "bla",
children: [
{
id: 97,
name: "bla"
},
{
id: 56,
name: "bla"
}
]
}
]
}
]
},
{
id: 15,
name: "bla",
children: [
{
id: 263,
name: "bla",
children: [{ id: 868, name: "bla" }, { id: 979, name: "bla" }]
},
{ id: 483, name: "bla" },
{
id: 445,
name: "bla",
children: [{ id: 423, name: "bla" }, { id: 436, name: "bla" }]
}
]
}
];
How would I grab a certain object by key that might be deeply nested, using recursion?
I have tried this, but this won't work for nesting deeper than 2 levels, it then just returns undefined:
const findItemNested = (arr, itemId, nestingKey) => {
for (const i of arr) {
console.log(i.id);
if (i.id === itemId) {
return i;
}
if (i[nestingKey]) {
findItemNested(i[nestingKey], itemId, nestingKey);
}
}
};
The result should be:
const res = findItemNested(array, 959, "children"); >> { id: 959, name: "bla" }
This can perhaps also be achieved using .find, or just to flatten the array (by the children key), but using recursion seems like the most logical solution to me. Does anybody have a solution to this?
Thanks in advance :).
You might use a recursive reduce:
const array=[{id:1,name:"bla",children:[{id:23,name:"bla",children:[{id:88,name:"bla"},{id:99,name:"bla"}]},{id:43,name:"bla"},{id:45,name:"bla",children:[{id:43,name:"bla"},{id:46,name:"bla"}]}]},{id:12,name:"bla",children:[{id:232,name:"bla",children:[{id:848,name:"bla"},{id:959,name:"bla"}]},{id:433,name:"bla"},{id:445,name:"bla",children:[{id:443,name:"bla"},{id:456,name:"bla",children:[{id:97,name:"bla"},{id:56,name:"bla"}]}]}]},{id:15,name:"bla",children:[{id:263,name:"bla",children:[{id:868,name:"bla"},{id:979,name:"bla"}]},{id:483,name:"bla"},{id:445,name:"bla",children:[{id:423,name:"bla"},{id:436,name:"bla"}]}]}];
const findItemNested = (arr, itemId, nestingKey) => (
arr.reduce((a, item) => {
if (a) return a;
if (item.id === itemId) return item;
if (item[nestingKey]) return findItemNested(item[nestingKey], itemId, nestingKey)
}, null)
);
const res = findItemNested(array, 959, "children");
console.log(res);
This should work:
function findByIdRecursive(array, id) {
for (let index = 0; index < array.length; index++) {
const element = array[index];
if (element.id === id) {
return element;
} else {
if (element.children) {
const found = findByIdRecursive(element.children, id);
if (found) {
return found;
}
}
}
}
}
You might also use recursion with Array.find like below
const array=[{id:1,name:"bla",children:[{id:23,name:"bla",children:[{id:88,name:"bla"},{id:99,name:"bla"}]},{id:43,name:"bla"},{id:45,name:"bla",children:[{id:43,name:"bla"},{id:46,name:"bla"}]}]},{id:12,name:"bla",children:[{id:232,name:"bla",children:[{id:848,name:"bla"},{id:959,name:"bla"}]},{id:433,name:"bla"},{id:445,name:"bla",children:[{id:443,name:"bla"},{id:456,name:"bla",children:[{id:97,name:"bla"},{id:56,name:"bla"}]}]}]},{id:15,name:"bla",children:[{id:263,name:"bla",children:[{id:868,name:"bla"},{id:979,name:"bla"}]},{id:483,name:"bla"},{id:445,name:"bla",children:[{id:423,name:"bla"},{id:436,name:"bla"}]}]}];
function findById(arr, id, nestingKey) {
// if empty array then return
if(arr.length == 0) return
// return element if found else collect all children(or other nestedKey) array and run this function
return arr.find(d => d.id == id)
|| findById(arr.flatMap(d => d[nestingKey] || []), id)
|| 'Not found'
}
console.log(findById(array, 12, 'children'))
console.log(findById(array, 483, 'children'))
console.log(findById(array, 1200, 'children'))
We use object-scan for most of our data processing. It's awesome for all sorts of things, but does take a while to wrap your head around. This is how one could answer your question:
// const objectScan = require('object-scan');
const find = (data, id) => objectScan(['**(^children$).id'], {
abort: true,
rtn: 'parent',
useArraySelector: false,
filterFn: ({ value }) => value === id
})(data);
const array=[{id:1,name:"bla",children:[{id:23,name:"bla",children:[{id:88,name:"bla"},{id:99,name:"bla"}]},{id:43,name:"bla"},{id:45,name:"bla",children:[{id:43,name:"bla"},{id:46,name:"bla"}]}]},{id:12,name:"bla",children:[{id:232,name:"bla",children:[{id:848,name:"bla"},{id:959,name:"bla"}]},{id:433,name:"bla"},{id:445,name:"bla",children:[{id:443,name:"bla"},{id:456,name:"bla",children:[{id:97,name:"bla"},{id:56,name:"bla"}]}]}]},{id:15,name:"bla",children:[{id:263,name:"bla",children:[{id:868,name:"bla"},{id:979,name:"bla"}]},{id:483,name:"bla"},{id:445,name:"bla",children:[{id:423,name:"bla"},{id:436,name:"bla"}]}]}];
console.log(find(array, 12));
// => { id: 12, name: 'bla', children: [ { id: 232, name: 'bla', children: [ { id: 848, name: 'bla' }, { id: 959, name: 'bla' } ] }, { id: 433, name: 'bla' }, { id: 445, name: 'bla', children: [ { id: 443, name: 'bla' }, { id: 456, name: 'bla', children: [ { id: 97, name: 'bla' }, { id: 56, name: 'bla' } ] } ] } ] }
console.log(find(array, 483));
// => { id: 483, name: 'bla' }
console.log(find(array, 959));
// => { id: 959, name: 'bla' }
console.log(find(array, 1200));
// => undefined
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.7.1"></script>
Disclaimer: I'm the author of object-scan
You can do:
const array=[{id:1,name:"bla",children:[{id:23,name:"bla",children:[{id:88,name:"bla"},{id:99,name:"bla"}]},{id:43,name:"bla"},{id:45,name:"bla",children:[{id:43,name:"bla"},{id:46,name:"bla"}]}]},{id:12,name:"bla",children:[{id:232,name:"bla",children:[{id:848,name:"bla"},{id:959,name:"bla"}]},{id:433,name:"bla"},{id:445,name:"bla",children:[{id:443,name:"bla"},{id:456,name:"bla",children:[{id:97,name:"bla"},{id:56,name:"bla"}]}]}]},{id:15,name:"bla",children:[{id:263,name:"bla",children:[{id:868,name:"bla"},{id:979,name:"bla"}]},{id:483,name:"bla"},{id:445,name:"bla",children:[{id:423,name:"bla"},{id:436,name:"bla"}]}]}];
const findItemNested = (arr, itemId, nestingKey) => arr.reduce((a, c) => {
return a.length
? a
: c.id === itemId
? a.concat(c)
: c[nestingKey]
? a.concat(findItemNested(c[nestingKey], itemId, nestingKey))
: a
}, []);
const res = findItemNested(array, 959, "children");
if (res.length) {
console.log(res[0]);
}
This will use recursive find by level, it'll try to find the item in array and then call itself with the children of each item in the array:
New browsers will have Array.prototype.flatten but in this case I've added the flatten function separately.
const array = [{"id":1,"name":"bla","children":[{"id":23,"name":"bla","children":[{"id":88,"name":"bla"},{"id":99,"name":"bla"}]},{"id":43,"name":"bla"},{"id":45,"name":"bla","children":[{"id":43,"name":"bla"},{"id":46,"name":"bla"}]}]},{"id":12,"name":"bla","children":[{"id":232,"name":"bla","children":[{"id":848,"name":"bla"},{"id":959,"name":"bla"}]},{"id":433,"name":"bla"},{"id":445,"name":"bla","children":[{"id":443,"name":"bla"},{"id":456,"name":"bla","children":[{"id":97,"name":"bla"},{"id":56,"name":"bla"}]}]}]},{"id":15,"name":"bla","children":[{"id":263,"name":"bla","children":[{"id":868,"name":"bla"},{"id":979,"name":"bla"}]},{"id":483,"name":"bla"},{"id":445,"name":"bla","children":[{"id":423,"name":"bla"},{"id":436,"name":"bla"}]}]}];
const flatten = (arr) =>
arr.reduce((result, item) => result.concat(item), []);
const findBy = (findFunction, subItemsKey) => (array) =>
//array is empty (can be when children of children of children does not exist)
array.length === 0
? undefined //return undefined when array is empty
: array.find(findFunction) || //return item if found
findBy(findFunction, subItemsKey)(//call itself when item is not found
flatten(
//take children from each item and flatten it
//([[child],[child,child]])=>[child,child,child]
array.map((item) => item[subItemsKey] || []),
),
);
const findChildrenById = (array) => (value) =>
findBy((item) => item.id === value, 'children')(array);
const findInArray = findChildrenById(array);
console.log('found', findInArray(99));
console.log('not found', findInArray({}));
You need to iterate through your objects and then need to be parse each object using recursion. Try the answer mentioned here: JavaScript recursive search in JSON object
code:
`function findNode(id, currentNode) {
var i,
currentChild,
result;
if (id == currentNode.id) {
return currentNode;
} else {
// Use a for loop instead of forEach to avoid nested functions
// Otherwise "return" will not work properly
for (i = 0; i < currentNode.children.length; i += 1) {
currentChild = currentNode.children[i];
// Search in the current child
result = findNode(id, currentChild);
// Return the result if the node has been found
if (result !== false) {
return result;
}
}
// The node has not been found and we have no more options
return false;
}
}`

Find object by property path in nested array of objects

I have such object:
var obj = [
{
name: 'ob_1',
childFields: [],
},
{
name: 'ob_2',
childFields: [
{
name: 'ob_2_1',
childFields: [
{
name: 'ob_3_1',
childFields: [],
test: 124
},
],
},
],
},
]
function getObjectByNamePath(path, fieds) {
const pathArr = path.split('.');
const result = fieds.find(field => {
if (pathArr.length > 1) {
if (field.name === pathArr[0] && field.childFields.length) {
const newPath = pathArr.slice(1, pathArr.length).join('.');
return getObjectByNamePath(newPath, field.childFields);
}
return false;
} else {
if (field.name === pathArr[0]) {
return true;
} else {
return false;
}
}
});
return result;
}
I want to get object by name values path:
console.log(getObjectByNamePath('ob_2.ob_2_1.ob_3_1', obj))
I tried this, but it doesn't work correct and i feel that there is more elegant way to achieve what i want. Thanks.
You could iterate the childFields and find the name for this level, then take the next level name.
function getObjectByNamePath(path, array) {
return path
.split('.')
.reduce(
({ childFields = [] } = {}, name) => childFields.find(o => o.name === name),
{ childFields: array }
);
}
var obj = [{ name: 'ob_1', childFields: [], }, { name: 'ob_2', childFields: [ { name: 'ob_2_1', childFields: [ { name: 'ob_3_1', childFields: [], test: 124 }] }] }];
console.log(getObjectByNamePath('ob_2.ob_2_1.ob_3_1', obj));
console.log(getObjectByNamePath('ob_1', obj));
console.log(getObjectByNamePath('foo.bar', obj));
.as-console-wrapper { max-height: 100% !important; top: 0; }
A recursive solution.
var obj = [{ name: 'ob_1', childFields: [], }, { name: 'ob_2', childFields: [ { name: 'ob_2_1', childFields: [ { name: 'ob_3_1', childFields: [], test: 124 }] }] }]
function getObjectByNamePath(path, obj) {
const [currentPath, ...restPaths] = path.split('.');
const nextObj = (obj.find(e => e.name === currentPath))
if(!restPaths.length) return nextObj;
return getObjectByNamePath(restPaths.join('.'), nextObj.childFields || []);
}
// Test Cases
console.log(getObjectByNamePath('ob_2.ob_2_1.ob_3_1', obj))
console.log(getObjectByNamePath('ob_2.ob_2_1.ob_3_1.fakePath', obj))
console.log(getObjectByNamePath('ob_1', obj))
console.log(getObjectByNamePath('', obj))

Categories

Resources