How add new Key/value in nested child object in javascript? - javascript

I need to add new key/value pair into nested object array.
this is exisiting array
[{
"featureId": "67d6e1bf-3919-4dcc-b636-236ab41d431b",
"featureName": "Test name 1",
"rules": [
{
"ruleId": "a9ab3ce2-e69c-4c0c-b561-1107baed1e68",
"ruleName": "Sub test 1",
},
{
"ruleId": "a9ab3ce2-e69c-4c0c-b561-1107baed1e68",
"ruleName": "Sub Test 2",
},
{
"ruleId": "a8003493-4471-4c8a-85c1-b15706359bb3",
"ruleName": "Sub Test Three",
}
]
},
{...}
]
I need to add additional property into the rules object items.
Expected output is
[{
"featureId": "67d6e1bf-3919-4dcc-b636-236ab41d431b",
"featureName": "Test name 1",
"rules": [
{
"ruleId": "a9ab3ce2-e69c-4c0c-b561-1107baed1e68",
"ruleName": "Sub test 1",
"temp_id" : 1
},
{
"ruleId": "a9ab3ce2-e69c-4c0c-b561-1107baed1e68",
"ruleName": "Sub Test 2",
"temp_id" : 1
},
{
"ruleId": "a8003493-4471-4c8a-85c1-b15706359bb3",
"ruleName": "Sub Test Three",
"temp_id" : 1
}
]
},
{...}
]
I need to add temp_id property dynamically.
I tried below its not working as expected
Object.keys(_this.existingConfigurations).map((key)=>_this.existingConfigurations[key].rules).reduce((n,id)=>n).map((ny,ni)=>{return {...ny, temp_id : uuid.v4()}});
Here "_this.existingConfigurations" is variable which have the data, i need to do above modification and send to next level.

You could solve this with a couple of maps and a healthy dose of object restructuring:
const initial = [
{
featureId: "67d6e1bf-3919-4dcc-b636-236ab41d431b",
featureName: "Test name 1",
rules: [
{
ruleId: "a9ab3ce2-e69c-4c0c-b561-1107baed1e68",
ruleName: "Sub test 1",
temp_id: 1,
},
{
ruleId: "a9ab3ce2-e69c-4c0c-b561-1107baed1e68",
ruleName: "Sub Test 2",
temp_id: 1,
},
{
ruleId: "a8003493-4471-4c8a-85c1-b15706359bb3",
ruleName: "Sub Test Three",
temp_id: 1,
},
],
},
];
const result = initial.map((feature) => ({
...feature,
rules: feature.rules.map((rule) => ({ ...rule, temp_id: 1 })),
}));

var existingConfigurations = [{
"featureId": "67d6e1bf-3919-4dcc-b636-236ab41d431b",
"featureName": "Test name 1",
"rules": [
{
"ruleId": "a9ab3ce2-e69c-4c0c-b561-1107baed1e68",
"ruleName": "Sub test 1",
},
{
"ruleId": "a9ab3ce2-e69c-4c0c-b561-1107baed1e68",
"ruleName": "Sub Test 2",
},
{
"ruleId": "a8003493-4471-4c8a-85c1-b15706359bb3",
"ruleName": "Sub Test Three",
}
]
}];
existingConfigurations = _.map(existingConfigurations, (item) => ({ ...item, rules: _.map(_.get(item, 'rules'), (rule, idx) => ({ ...rule, temp_id: idx })) }));
console.log(existingConfigurations);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>
You can refer to the following example.
Hope this help!

Related

How to convert array of object into nested array of object in Javascript?

I am having an array of objects like this
[
{
name: "dhanush",
goals: ["goal 1","goal 2"],
goalAmount: ["10000","20000"]
},
{
name: "kumar",
goals: ["goal 3", "goal 4"],
goalAmount: ["30000","40000"]
},
{
name: "test",
goals: ["goal 5"],
goalAmount: ["50000"],
}
]
Is that possible to convert the above array of object into the below structure like this
[
{
"name": "dhanush",
"goals": "---",
"goalAmount":"---",
"subRows": [
{
"name": "",
"goals": "goal 1",
"goalAmount":" 10000"
},
{
"name": "",
"goals": "goal 2",
"goalAmount":" 20000"
}
]
},
{
"name": "kumar",
"goals": "---",
"goalAmount":"---",
"subRows": [
{
"name": "",
"goals": "goal 3",
"goalAmount":" 30000"
},
{
"name": "",
"goals": "goal 4",
"goalAmount":" 40000"
}
]
},
{
"name": "Test",
"goals": "goal 5",
"goalAmount":"50000"
}
]
In the first data, you can see the user has multiple goals (which means the array length is more than 1), If the goal length is more than one, need to create another key and move the goal data into the above structure like this.
Why I am doing this because I got an ask to create a table that needs to support expandable rows. I used #tanstack/react-table for this row expansion. Here you can find the working demo link - https://codesandbox.io/s/tanstack-table-expansion-1t77ks?file=/src/App.js
In the demo, you can see the row can expand. For the expansion that table requires the data format like this.
I tried to do something like this,
var data = [
{
name: "dhanush",
goals: ["goal 1","goal 2"]
},
{
name: "kumar",
goals: ["goal 3", "goal 4"]
},
{
name: "test",
goals: ["goal 5"]
}
]
let result = data.map((val,i) => {
return {
name: val.name,
...(val.goals.length === 1 && {goals: val.goals[0]}),
[val.goals.length > 1 && 'subRows']: data.map((t,j) => {
return{
name: "",
goals: val.goals[j]
}
}),
}
})
But the output I am getting like this instead of the actual structure
[
{
"name": "dhanush",
"subRows": [
{
"name": "",
"goals": "goal 1"
},
{
"name": "",
"goals": "goal 2"
},
{
"name": ""
}
]
},
{
"name": "kumar",
"subRows": [
{
"name": "",
"goals": "goal 3"
},
{
"name": "",
"goals": "goal 4"
},
{
"name": ""
}
]
},
{
"name": "test",
"goals": "goal 5",
"false": [
{
"name": "",
"goals": "goal 5"
},
{
"name": ""
},
{
"name": ""
}
]
}
]
Could you please help to achieve this?
This here
[val.goals.length > 1 && 'subRows']: data.map((tm j) => {
evaluates to false if there's 1 goal or less, and results in the string property false. Then you're mapping the whole data again inside that for some reason. Only map over the goals of the current element you're iterating over, the val.goals.
Because the different possible resulting objects are pretty differently strucured, I think this would be easier to manage if they were entirely separate - return { name, goals: goals[0] } if there's only one goal, and return a completely different object mapping over the goals otherwise.
var data=[{name:"dhanush",goals:["goal 1","goal 2"],goalAmount:["10000","20000"]},{name:"kumar",goals:["goal 3","goal 4"],goalAmount:["30000","40000"]},{name:"test",goals:["goal 5"],goalAmount:["50000"]}];
const result = data.map(({ name, goals, goalAmount }) => {
return goals.length === 1
? { name, goals: goals[0], goalAmount: goalAmount[0] }
: {
name,
goals: '---',
subRows: goals.map(
(goal, i) => ({ name: '', goal, goalAmount: goalAmount[i] })
)
};
});
console.log(result);
Don't try to do this all in a single object literal, it's a confusing way to create properties conditionally. Just write normal conditional statements.
To get the goalAmount, use the index argument to the map() callback function so you can get the corresponding element in another array.
var data = [
{
name: "dhanush",
goals: ["goal 1","goal 2"],
goalAmount: ["10000","20000"]
},
{
name: "kumar",
goals: ["goal 3", "goal 4"],
goalAmount: ["30000","40000"]
},
{
name: "test",
goals: ["goal 5"],
goalAmount: ["50000"],
}
]
var result = data.map(({
name,
goals,
goalAmount
}) => {
let item = {
name
};
if (goals.length == 1) {
item.goals = goals[0];
item.goalAmount = goalAmount[0];
} else {
item.goals = "---";
item.subRows = goals.map((g, i) => ({
name: "",
goals: g,
goalAmount: goalAmount[i]
}));
}
return item;
});
console.log(result);

Creating a nested array from a flat array - JavaScript

I'm looking to create a nested array based on reading a flat array. An example of the flat array I am reading is this:
const flatItems = [
{
"code": "CODE1",
"title": "Title 1",
"question": "Question 1",
"order": 0,
},
{
"code": "CODE2",
"title": "Title 2",
"question": "Question 2",
"order": 1,
},
{
"code": "CODE3",
"title": "Title 3",
"question": "Question 3",
"order": 2,
},
{
"code": "CODE4",
"title": "Title 4",
"question": "Question 4",
"order": 3,
},
];
And ideally I would like to place this into groups of 'Yes's and 'No's. The flat array is already in the correct order. There will only ever be one item in the 'Yes's but can have many in the 'No's depending on any conditions.
const treeItems = {
question: "Question 1",
options: [
{
value: "Yes",
items: [
{
code: "CODE1",
title: "Title 1"
}
]
},
{
value: "No",
question: "Question 2"
options: [
{
value: "Yes",
items: [
{
code: "CODE2",
title: "Title 2"
}
]
},
{
value: "No",
items: [
{
code: "CODE3",
title: "Title 3"
},
{
code: "CODE4",
title: "Title 4"
}
]
}
]
}
]
};
I am aware that reduce may be the best approach here, but would anyone have any good examples or recommended practices as how I should go about doing this?
If you want to group these items use "Yes" and "No" as the properties of the final object.
Using Array.reduce() sounds solid in this case.
Not sure how you want to group because your JSON is inconsistent.
const flatItems = [
{
"code": "CODE1",
"title": "Title 1",
"question": "Question 1",
"order": 0,
},
{
"code": "CODE2",
"title": "Title 2",
"question": "Question 2",
"order": 1,
},
{
"code": "CODE3",
"title": "Title 3",
"question": "Question 3",
"order": 2,
},
{
"code": "CODE4",
"title": "Title 4",
"question": "Question 4",
"order": 3,
},
];
const groupedObject = flatItems.reduce((tmpGroupedObject, item) => {
const groupingProperty = item.order < 2 ? "Yes" : "No"; /// grouping decision
if (!Array.isArray(tmpGroupedObject[groupingProperty])) {
tmpGroupedObject[groupingProperty] = []; /// make Obj["Yes"] an array
}
tmpGroupedObject[groupingProperty].push(item);
return tmpGroupedObject;
}, {});
console.log(groupedObject);
As mentioned in the comments, I'm confused by the requested output. I especially don't understand why CODE3 and CODE4 are on the same level, and not nested as another Yes/No pair. But we can write a fairly simple recursion to do that:
const convert = ([{code, title, question} = {}, ...items]) => ({
question,
options: [
{value: "Yes", items: [{code, title}]},
{value: "No", ... (items .length < 3 ? {items: items .map (({code, title}) => ({code, title}))} : convert (items))}
]
})
const flatItems = [{code: "CODE1", title: "Title 1", question: "Question 1", order: 0}, {code: "CODE2", title: "Title 2", question: "Question 2", order: 1}, {code: "CODE3", title: "Title 3", question: "Question 3", order: 2}, {code: "CODE4", title: "Title 4", question: "Question 4", order: 3}]
console .log (
convert (flatItems)
)
.as-console-wrapper {max-height: 100% !important; top: 0}
However by changing < 3 to < 2, we get what I think of as a much more logical grouping:
const convert = ([{code, title, question} = {}, ...items]) => ({
question,
options: [
{value: "Yes", items: [{code, title}]},
{value: "No", ... (items .length < 2 ? {items: items .map (({code, title}) => ({code, title}))} : convert (items))}
]
})
const flatItems = [{code: "CODE1", title: "Title 1", question: "Question 1", order: 0}, {code: "CODE2", title: "Title 2", question: "Question 2", order: 1}, {code: "CODE3", title: "Title 3", question: "Question 3", order: 2}, {code: "CODE4", title: "Title 4", question: "Question 4", order: 3}]
console .log (
convert (flatItems)
)
.as-console-wrapper {max-height: 100% !important; top: 0}
I hope one of these does what you want.
Also, again, welcome to StackOverflow. Next time, please be sure to post your own attempted solution in the question. Even if it's not working properly, we can often either help you fix it, or explain why it's headed down the wrong path altogether.

How to reformat object using its property value as property key?

how can I assign object property value as property key?
I have a set of data:
const mydata = [
{
"id": 001,
"value": "Value 1",
"title": "Title 1"
},
{
"id": 002,
"value": [
{
"Name": "Name 1",
"Age": "20"
},
{
"Name": "Name 2",
"Age": "30"
},
],
"title": "Title 2"
},
]
I want to reformat it to become:
const mydata = [
{
"Title 1": "Value 1"
},
{
"Title 2": [
{
"Name": "Name 1",
"Age": "20"
},
{
"Name": "Name 2",
"Age": "30"
},
]
},
]
I have tried this code to achieve it:
mydata.map((dt: any) => {
dt.title: dt.value
});
However, it seems not working.
Any idea how can I reformat it to the one I desire?
Thanks.
Please use following code.
Reference URL How to use a variable for a key in a JavaScript object literal?
const mydata = [
{
"id": 001,
"value": "Value 1",
"title": "Title 1"
},
{
"id": 002,
"value": [
{
"Name": "Name 1",
"Age": "20"
},
{
"Name": "Name 2",
"Age": "30"
},
],
"title": "Title 2"
},
];
let reData = [];
mydata.forEach((dt)=>{
reData.push({[dt.title]: dt.value});
});
console.log(reData);
If you want to transform the array to a different type of variable, use [reduce][1]
const mydata = [
{
id: 001,
value: "Value 1",
title: "Title 1",
},
{
id: 002,
value: [
{
Name: "Name 1",
Age: "20",
},
{
Name: "Name 2",
Age: "30",
},
],
title: "Title 2",
},
];
const data = mydata.reduce(
(acc, cur) => ({ ...acc, [cur.title]: cur.value }),
{}
);
console.log(data);
Your map function has an error, and your key assignment has another one. Let's fix it.
const newData = mydata.map((dt: any) => ({
[dt.title]: dt.value,
}));
First: You can't return an object from an arrow function without parenthesis, if you don't use it, the code will think it is a function body not an object.
Second: If you want to return a value as a key, you need put it inside "[ ]" (Square brackets)
Just that, simple mistakes, at the end you came up with the right logic to solve it
Add brackets around the return value.
Use square brackets for a computed property name.
const mydata = [
{
"id": 001,
"value": "Value 1",
"title": "Title 1"
},
{
"id": 002,
"value": [
{
"Name": "Name 1",
"Age": "20"
},
{
"Name": "Name 2",
"Age": "30"
},
],
"title": "Title 2"
},
];
const res = mydata.map(({value, title})=>({[title]: value}));
console.log(res);

Filter inside a nested array with objects

I have an array that contains three book objects. Each book object has an array of bookIds . I want to filter by bookId (3,1) in a fast and efficient way since my array will grow up easly in the future. I tried with map, but it change my original array even with a deepCopy ! Is there a way to use the filter function instead without using recursivity ?
this.booksList =
[
{
"books": [
{
"bookId": 3
},
{
"bookId": 2
}
],
"id": 1,
"name": "Name 1",
"description": "desc 1"
},
{
"books": [
{
"bookId": 5
},
{
"bookId": 2
}
],
"id": 2,
"name": "Name 2",
"description": "desc 2"
},
{
"books": [
{
"bookId": 1
},
{
"bookId": 3
}
],
"id": 3,
"name": "Name 3",
"description": "desc 3"
}
]
The map approach :
let results = this.books.map(function (book) {
book.books = book.books.filter(x => x.bookId == 1 || x.bookId == 3);
return book;
}).filter(({ books }) => books.length);
Result with map : not expected result !
[
{
"books": [
{
"bookId": 3
}
],
"id": 1,
"name": "Name 1",
"description": "desc 1"
},
{
"books": [
{
"bookId": 1
},
{
"bookId": 3
}
],
"id": 3,
"name": "Name 3",
"description": "desc 3"
}
]
expected results :
[
{
"books": [
{
"bookId": 3
},
{
"bookId": 2
}
],
"id": 1,
"name": "Name 1",
"description": "desc 1"
},
{
"books": [
{
"bookId": 1
},
{
"bookId": 3
}
],
"id": 3,
"name": "Name 3",
"description": "desc 3"
}
]
Thanks,
I think you are looking for filter and some -
const input =
[{books:[{bookId:3},{bookId:2}],id:1,name:"Name 1",description:"desc 1"},{books:[{bookId:5},{bookId:2}],id:2,name:"Name 2",description:"desc 2"},{books:[{bookId:1},{bookId:3}],id:3,name:"Name 3",description:"desc 3"}]
const query =
[3, 1]
const result =
input.filter(({ books = [] }) =>
books.some(({ bookId = null }) => query.includes(bookId))
)
console.log(JSON.stringify(result, null, 2))
Output -
[
{
"books": [
{
"bookId": 3
},
{
"bookId": 2
}
],
"id": 1,
"name": "Name 1",
"description": "desc 1"
},
{
"books": [
{
"bookId": 1
},
{
"bookId": 3
}
],
"id": 3,
"name": "Name 3",
"description": "desc 3"
}
]
const booksList=[
{books:[{bookId:3},{bookId:2}],id:1,name:"Name 1",description:"desc 1"},
{books:[{bookId:5},{bookId:2}],id:2,name:"Name 2",description:"desc 2"},
{books:[{bookId:1},{bookId:3}],id:3,name:"Name 3",description:"desc 3"},
];
const byBookIDs = (...IDs) =>
booksList.filter(b => b.books.some(b => IDs.includes(b.bookId)));
console.log(byBookIDs(1, 3));
MDN Array Filter - to return a subset
MDN Array Some - to match (and return) as soon as some
MDN Array Includes - to find item in array

Filter nested collections using Rxjs

I need to filter the following json data structure using Rxjs operators,
consider the following example, we have list of hotels and each hotel as rooms underneath it, we need to get all hotels that have available rooms in it,
so consider the following input as:
var hotels = [
{
"hotel": "hotel 1",
"rooms": [
{
"name": "room 1",
"flexible": true
},
{
"name": "room 2",
"flexible": false
}
]
},
{
"hotel": "hotel 2",
"rooms": [
{
"name": "room 1",
"flexible": false
},
{
"name": "room 2",
"flexible": false
}
]
}
];
and the desired output should be as the following:
var availableRooms = [
{
"hotel": "hotel 1",
"rooms": [
{
"name": "room 1",
"flexible": true
}
]
}
];
so How can I apply this in Rxjs?
Thanks
Are you sure that we need a RxJx?
function isAvailable(room) { return room.flexible };
hotels
.map(hotel => ({ ...hotel, rooms: hotel.rooms.filter(isAvailable) }))
.filter(hotel => hotel.rooms.length);
If hotel goes one by one - then use the same approach but with RxJs operators.
Edited
Solution with RxJS
function isAvailable(room) { return room.flexible };
from(hotels).pipe(
map(hotel => ({ ...hotel, rooms: hotel.rooms.filter(isAvailable) })),
filter(hotel => hotel.rooms.length),
toArray(),
).subscribe(console.log)

Categories

Resources