Replace array in nested object in Javascript - javascript

I have spent a good part of the day trying to replace arrays of an existing nested object but I can't figure out how to do it. This is my original object:
{
"id": "a8df1653-238a-4f23-fe42-345c5d928b34",
"webSections": {
"id": "x58654a9-283b-4fa6-8466-3f7534783f8",
"sections": [
{
"id": "92d7e428-4a5b-4f7e-bc7d-b761ca018922",
"title": "Websites",
"questions": [
{
id: 'dee6e3a6-f207-f3db-921e-32a0b745557',
text: 'Website questions',
items: Array(11)
}
]
},
{
"id": "79e42d88-7dd0-4f70-b6b4-dea4b4a64ef3",
"title": "Blogs",
"questions": [
...
]
},
{
"id": "439ded88-d7ed0-de70-b6b4-dea4b4a64e840",
"title": "App questions",
"questions": [
...
]
}
]
}
I would like replace the question arrays in the original object or in a copy of it.
const newMenu = [
{id: '34bb96c7-1eda-4f10-8acf-e6486296f4dd', text: 'Website questions', items: Array(24)},
{id: '520c2d3f-6117-4f6a-904f-2477e3347472', text: 'Blog questions', item: Array(7)},
{id: '302b658a-9d8c-4f53-80f6-3f2275bfble', title: 'App questions', items: Array(14)}
]
I am trying to do this by its index but unfortunately it doesn't work.
webSections.sections.forEach((item, index) => {
return webSections.sections[index].questions, newMenu[index]);
}
Does anyone see what am I doing wrong?

The value returned from the callback passed to forEach will not be used anywhere.
If you want to avoid mutating the original object and update questions, you can use Array.prototype.map and object spread syntax.
const object = {
"id": "a8df1653-238a-4f23-fe42-345c5d928b34",
"webSections": {
"id": "x58654a9-283b-4fa6-8466-3f7534783f8",
"sections": [
{
"id": "92d7e428-4a5b-4f7e-bc7d-b761ca018922",
"title": "Websites",
"questions": [
{
id: 'dee6e3a6-f207-f3db-921e-32a0b745557',
...
const updatedObject = {
...object,
webSections: {
...object.webSections,
sections: object.webSections.sections.map((section, index) => ({...section, questions: newMenu[index]}))
}
}
If you just want to mutate the original object
object.webSections.sections.forEach((_, index) => {
section.questions = newMenu[index]
})

const newSections = myObj.webSections.sections.map((obj, index) => {
const newQuestions = newItems[index];
return {
...obj,
questions: [newQuestions],
};
});
console.log(newSections);
MyObj is the main object.
This shall produce the new sections array you can combine it with your main object I suppose...
#Ramesh Reddy has the most thorough answer.

The simplest way if you don't care about mutation is:
myObject.webSections.sections.forEach((section, index) => {
section.questions = newMenu[index].items;
})
You have used your 'forEach' with wrong syntax. Check MDN on how it's used.

Related

TypeError: Cannot read properties of undefined (reading 'product-1')

So I am trying to display JSON data in my React.js project, but I am getting an error that I can't figure out. I've spent 2 days trying to figure it out, but had no luck
The JSON data: (filename: products.json)
{
"product-1": [
{
"id": 1,
"name": "product-1",
}
],
"product-2": [
{
"id": 2,
"name": "product-2",
}
],
"product-3": [
{
"id": 3,
"name": "product-3",
}
]
}
My javascript:
const productsData = Object.keys(backendData).map(key => {
return {
[key]: backendData[key]
}
})
console.log(productsData[0].products["product-1"][0].id)
error:
Log of backEndData:
Because productsData will return you array like this:
[
{ "product-1": [
{
"id": 1,
"name": "product-1",
}
]},
{"product-2": [
{
"id": 2,
"name": "product-2",
}
]}, ....
]
Meaning this is array of objects, where each object have one key-value pair, where key is name and value is an array.
If you want to access id then you should do like this:
productsData[0]["product-1"][0].id
UPDATED AFTER UPDATE OF OP
Since your backendData value does not match product.json, I will ignore that product.json and write you the solution which will work for the value of backendData you just provided.
const productsData = backendData.products;
const id = productsData[0]["product-1"][0].id;

Porblem on Getting Array Inside of Array

I have a problem on an object inside of an array and I wanted to display only that as an array.
data1
const data1 = [
{
"id": "01",
"info": "fefef",
"sub": "hieei",
"details": {
"data": "fruits"
}
},
{
"id": "02",
"info": "fefef",
"sub": "hieei",
"details": {
"data": "things"
}
}
]
expected output
const final= [
{
"data": "fruits"
},
{
"data": "things"
}
]
Code
const final = data.map((data) => { ...data})
map over the array and return a new object using the details property. If you don't return a new object, your new array will still carry references to the objects in the original array. So if you change a value of a property in that original array, that change will be reflected in the new array too, and you probably don't want that to happen.
const data1=[{id:"01",info:"fefef",sub:"hieei",details:{data:"fruits"}},{id:"02",info:"fefef",sub:"hieei",details:{data:"things"}}];
// Make sure you return a copy of the
// details object otherwise if you change the details
// of the original objects in the array
// the new mapped array will carry those object changes
// because the array objects will simply references to the old objects
const out = data1.map(obj => {
return { ...obj.details };
});
console.log(out);
Map through the array and extract its details property:
const data1 = [
{
"id": "01",
"info": "fefef",
"sub": "hieei",
"details": {
"data": "fruits"
}
},
{
"id": "02",
"info": "fefef",
"sub": "hieei",
"details": {
"data": "things"
}
}
]
const res = data1.map(e => e.details)
console.log(res)
Using map and destructuring will simplify.
const data1 = [
{
id: "01",
info: "fefef",
sub: "hieei",
details: {
data: "fruits",
},
},
{
id: "02",
info: "fefef",
sub: "hieei",
details: {
data: "things",
},
},
];
const res = data1.map(({ details: { data } }) => ({ data }));
console.log(res);
// if you just need the details object
const res2 = data1.map(({ details }) => details);
console.log(res2);

unable to assign array to object attributes in javascript

Object attribute only hold the first element of the assigned value
let groupedDepActivities=[]
groupedDepActivities.push({
id:1,
term_activity:{
terms:[{id:1},{from:'here'},{to:'there'},]
}
})
the console.log() result will be
*
term_activity:
terms: Array(1)
0:
id: "1"
[[Prototype]]: Object
length: 1
*
terms attribute only hold the first element(id:1) of the array not all
The console's output may be truncated, but your code works as expected.
let groupedDepActivities = []
groupedDepActivities.push({
id: 1,
term_activity: {
terms: [{
id: 1
}, {
from: 'here'
}, {
to: 'there'
}, ]
}
})
console.log(groupedDepActivities);
Output:
[
{
"id": 1,
"term_activity": {
"terms": [
{
"id": 1
},
{
"from": "here"
},
{
"to": "there"
}
]
}
}
]
Were you wanting terms to be a single object?
let groupedDepActivities = []
groupedDepActivities.push({
id: 1,
term_activity: {
terms: {
id: 1,
from: 'here',
to: 'there',
}
}
})
console.log(groupedDepActivities);
[
{
"id": 1,
"term_activity": {
"terms": {
"id": 1,
"from": "here",
"to": "there"
}
}
}
]
you are only pushing one object, this one:
{
id:1,
term_activity:{
terms:[{id:1},{from:'here'},{to:'there'},]
}
}
Need to distiguish when you are handling an object: {}, from an array [].
To dive deeper in your data structure for example you can do:
console.log(groupedDepActivities=[0].term_activity.terms[0])
Maybe its also useful to wrap your item to log in braces, as it appears as an object with names in the console, like this:
console.log({groupedDepActivities})
In case checking the names of the variables you log while you unfold them to check what do they hold make you more compfortable :)

Create a new object in Angular 11 app based on values in another array of objects

I am having an Angular 11 app in which I have an array of objects as shown below.
details = [
{
"name": "firstName",
"content": "Tom"
},
{
"name": "lastName",
"content": "Smith"
},
{
"name": "email",
"content": "tomsmith#test.com"
}
]
I want to create an object from above array as shown below.
output = {
firstName: {value: "Tom"},
lastName: {value: "Smith"},
email: {value: "tomsmith#test.com"}
}
For simplicity I have only shown 3 objects in the details array but there can be any number of them. So I want the conversion to happen irrespective of the number of objects in the details array. How can I create the above output object? Please help me out.
you could do with Array#reduce.
const details = [ { "name": "firstName", "content": "Tom" }, { "name": "lastName", "content": "Smith" }, { "name": "email", "content": "tomsmith#test.com" } ];
const res = details.reduce(
(acc, {name, content: value}) => (acc[name] = {value}, acc), {}
);
console.log(res)
Not that I'm against to the other answers proposed. As an alternative you can also do it with the help of a "for-of" loop and applying destructured assignment.
const details = [ { "name": "firstName", "content": "Tom" }, { "name": "lastName", "content": "Smith" }, { "name": "email", "content": "tomsmith#test.com" } ];
let result = {}
for ({ name: n, content: value } of details) { result[n] = { value: value }; }
console.log(result)
MDN Reference - Deconstructuring Assignment
Map the array to an array of [name, { value }] pairs, and convert to an object using Object.fromEntries().
With Typescript you'll need to set the target as ES2019 at least in your TS config, and it doesn't require any type definition (TS Playground).
const details = [{"name":"firstName","content":"Tom"},{"name":"lastName","content":"Smith"},{"name":"email","content":"tomsmith#test.com"}]
const result = Object.fromEntries(
details.map(({ name, content: value }) => [name, { value }])
)
console.log(result)

Loop through JSON array of objects and get the properties based on the matching IDs from objects

My target is if the id from digital_assets and products matches then get the value of URL fro digital_assets and ProductName from products object. I'm able to traverse through the object and get the values of digital_assets and products but need some help to compare these two objects based on IDs to get the value of URL and ProductName. Below is what I've done so far.
var data = [{
"digital_assets": [{
"id": "AA001",
"url": "https://via.placeholder.com/150"
},{
"id": "AA002",
"url": "https://via.placeholder.com/150"
}]
}, {
"products": [{
"id": ["BB001", "AA001"],
"ProductName": "PROD 485"
},{
"id": ["BB002", "AA002"],
"ProductName": "PROD 555"
}]
}
];
$.each(data, function () {
var data = this;
//console.log(data);
$.each(data.digital_assets, function () {
var dAssets = this,
id = dAssets['id'];
// console.log(id);
});
$.each(data.products, function () {
var proData = this,
prod_id = proData['id'];
// console.log(prod_id);
$.each(prod_id, function () {
var arr_id = this;
console.log(arr_id);
});
});
});
Do I need to create new arrays and push the values into the new arrays? Then concat() these array to one. ? Bit lost any help will be appreciated.
Here is one way you can do this via Array.reduce, Array.includes, Object.entries and Array.forEach:
var data = [{ "digital_assets": [{ "id": "AA001", "url": "https://via.placeholder.com/150" }, { "id": "AA002", "url": "https://via.placeholder.com/150" } ] }, { "products": [{ "id": ["BB001", "AA001"], "ProductName": "PROD 485" }, { "id": ["BB002", "AA002"], "ProductName": "PROD 555" } ] } ]
const result = data.reduce((r,c) => {
Object.entries(c).forEach(([k,v]) =>
k == 'digital_assets'
? v.forEach(({id, url}) => r[id] = ({ id, url }))
: v.forEach(x => Object.keys(r).forEach(k => x.id.includes(k)
? r[k].ProductName = x.ProductName
: null))
)
return r
}, {})
console.log(Object.values(result))
You can use Array.prototype.find, Array.prototype.includes and Array.prototype.map to achieve this very gracefully.
let data = [
{
"digital_assets": [
{
"id": "AA001",
"url": "https://via.placeholder.com/150"
},
{
"id": "AA002",
"url": "https://via.placeholder.com/150"
}
]
},
{
"products": [
{
"id": ["BB001", "AA001"],
"ProductName": "PROD 485"
},
{
"id": ["BB002","AA002"],
"ProductName": "PROD 555"
}
]
}
];
// Find the 'digital_assets' array
let assets = data.find(d => d['digital_assets'])['digital_assets'];
// Find the 'products' array
let products = data.find(d => d['products'])['products'];
// Return an array of composed asset objects
let details = assets.map(a => {
return {
id : a.id,
url : a.url
name : products.find(p => p.id.includes(a.id)).ProductName
};
});
console.log(details);
changed answer to fit your needs:
var data = [
{
"digital_assets": [
{
"id": "AA001",
"url": "https://via.placeholder.com/150"
},
{
"id": "AA002",
"url": "https://via.placeholder.com/150"
}
]
},
{
"products": [
{
"id": ["BB001", "AA001"],
"ProductName": "PROD 485"
},
{
"id": ["BB002","AA002"],
"ProductName": "PROD 555"
}
]
}
]
let matchingIds = [];
let data_assetsObject = data.find(element => {
return Object.keys(element).includes("digital_assets")
})
let productsObject = data.find(element => {
return Object.keys(element).includes("products")
})
data_assetsObject["digital_assets"].forEach(da => {
productsObject["products"].forEach(product => {
if (product.id.includes(da.id)){
matchingIds.push({
url: da.url,
productName: product.ProductName
})
}
})
})
console.log(matchingIds);
working fiddle: https://jsfiddle.net/z2ak1fvs/3/
Hope that helped. If you dont want to use a new array, you could also store the respective data within the element you are looping through.
Edit:
I think i know why i got downvoted. My example works by making data an object, not an array. changed the snippet to show this more clearly.
Why is data an array anyway? Is there any reason for this or can you just transform it to an object?
Edit nr2:
changed the code to meet the expectations, as i understood them according to your comments. it now uses your data structure and no matter whats in data, you can now search for the objects containing the digital_assets / products property.
cheers
https://jsfiddle.net/2b1zutvx/
using map.
var myobj = data[0].digital_assets.map(function(x) {
return {
id: x.id,
url: x.url,
ProductName: data[1].products.filter(f => f.id.indexOf(x.id) > -1).map(m => m.ProductName)
};
});

Categories

Resources