how to push array value to another array object value javascript - javascript

I've data response like this
{
"data": {
"product": {
"colors": ["#3498db", "#00ccff"],
"items": [
{
"label": "Phone",
"value": "23.00"
},
{
"label": "Notebook",
"value": "3.00"
}
]
}
}
}
and then i want push the colors inside items
expected: items have three(3) variable each of index
items: [
{
label: phone,
value: 23.00,
color: #3498db
}
]
i've try using push and concat but i got error "Cannot read property 'data' of undefined"
here my code
generaliseData(dashboardC) {
let genData = Object.assign({}, dashboardC)
if (genData.product.items.length > 0) {
for (let i of genData.product.items) {
i.value = parseInt(i.value)
for (let j of genData.product.colors) {
i = i.push(j)
}
}
console.log(genData)
}
}

You can use map to iterate through your list, expect to have the length of colors equal the length of item
const response = {
"data": {
"product": {
"colors": ["#3498db", "#00ccff"],
"items": [
{
"label": "Phone",
"value": "23.00"
},
{
"label": "Notebook",
"value": "3.00"
}
]
}
}
};
function addColorToItem(response) {
const product = response.data.product;
const colors = product.colors;
const items = product.items;
return items.map((item, index) => {
item.color = colors[index];
return item;
})
}
console.log(addColorToItem(response));

You could iterate items and assign a color.
var response = { data: { product: { colors: ["#3498db", "#00ccff"], items: [{ label: "Phone", value: "23.00" }, { label: "Notebook", value: "3.00" }] } } },
temp = response.data.product;
temp.items.forEach((o, i) => o.color = temp.colors[i]);
console.log(response);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You can use a simple forEach() loop for that result:
var data = {
"product": {
"colors": ["#3498db", "#00ccff"],
"items": [{
"label": "Phone",
"value": "23.00"
},
{
"label": "Notebook",
"value": "3.00"
}
]
}
};
data.product.items.forEach((item, index) => item.color = data.product.colors[index]);
console.log(data);

Related

How in JS to merge in one object two json objects where the ID of on object correspond on the same ID of the second object

My question relates to the fact I'm querying 2 different objects from DB and the result is in JSON. I need to merge them into one.
The 2 objects have in common this two key/value IRBId = ... and id = ... and they look as an example
OBJ 1
{
"data":{
"IRBs":{
"nodes":[
{
"id":"8",
"name":"Admin ",
},
{
"id":"9",
"name":"Again",
}
],
}
}
}
OBJ 2
{
"data":{
"informedConsentForms":{
"count":3,
"nodes":[
{
"id":"93",
...
"IRBId":"9",
},
{
"id":"92",
...
"IRBId":"8",
},
{
"id":"91",
...
"IRBId":"8",
}
],
}
},
As you will see above OBJ 2 and OBJ 1 corresponding with the same at IRBid and id.
What I need is to merge the two OBJ where IRBId OBJ 2 === id OBJ 1
The result I would expect after the merge is
OBJ merged
{
[{
"id":"93",
...
"IRBId":"9",
"irb": {
"name":"Again ",
...
}
},
{
"id":"92",
...
"IRBId":"8",
"irb": {
"name":"Admin ",
...
}
},
{
"id":"91",
...
"IRBId":"8",
"irb": {
"name":"Admin ",
...
}
],
},
I don't know how to make it looks like this.
Try using Array.reduce
Logic
Loop through second object data nodes
Find the matching nodes from object 1 data nodes.
Push to accumulator with required details. (I have added only the nodes that was mentioned in in Expected resut, you can add asmuch as you need.)
const obj1 = {
"data": {
"IRBs": {
"nodes": [
{
"id": "8",
"name": "Admin ",
},
{
"id": "9",
"name": "Again",
}
],
}
}
}
const obj2 = {
"data": {
"informedConsentForms": {
"count": 3,
"nodes": [
{
"id": "93",
"IRBId": "9",
},
{
"id": "92",
"IRBId": "8",
},
{
"id": "91",
"IRBId": "8",
}
],
}
},
};
const obj1List = obj1.data.IRBs.nodes;
const output = obj2.data.informedConsentForms.nodes.reduce((acc, curr) => {
const matchingNode = obj1List.find((item) => item.id === curr.IRBId);
if (matchingNode) {
acc.push({
id: curr.id,
IRBId: curr.IRBId,
irb: {
name: matchingNode.name
}
})
}
return acc;
}, []);
console.log(output);
You need to use the map function on the nodes in the first object to construct a new object that contains the second and first object's attributes.
const obj1 = {
"data": {
"IRBs": {
"nodes": [{
"id": "8",
"obj1": "one",
"name": "Admin ",
},
{
"id": "9",
"obj1": "two",
"name": "Again",
}
]
}
}
};
const obj2 = {
"data": {
"informedConsentForms": {
"count": 3,
"nodes": [{
"id": "93",
"obj2": "1",
"IRBId": "9",
},
{
"id": "92",
"obj2": "2",
"IRBId": "8",
},
{
"id": "91",
"obj2": "3",
"IRBId": "8",
}
],
}
}
};
const obj1Data = obj1.data.IRBs.nodes;
const obj2Data = obj2.data.informedConsentForms.nodes;
const res = obj2Data.map(item => {
const obj1Item = obj1Data.find(obj1Item => item.IRBId === obj1Item.id);
return obj1Item ? { ...item, "irb": { ...obj1Item}} : { ...item};
});
console.log(res);
i am using nested loop, try this one
const obj2 = {
"data":{
"informedConsentForms":{
"count":3,
"nodes":[
{
"id":"93",
"IRBId":"9",
},
{
"id":"92",
"IRBId":"8",
},
{
"id":"91",
"IRBId":"8",
}
],
}
},
}
const obj1 = {
"data":{
"IRBs":{
"nodes":[
{
"id":"8",
"name":"Admin ",
},
{
"id":"9",
"name":"Again",
}
],
}
}
}
const result = [];
const obj2Nodes = obj2.data.informedConsentForms.nodes;
for(let i = 0; i < obj2Nodes.length; i++) {
const obj1Nodes = obj1.data.IRBs.nodes
for(let j = 0; j < obj1Nodes.length; j++) {
if(obj2Nodes[i].IRBId === obj1Nodes[j].id) {
const {id, ...reObj1Nodes} = obj1Nodes[j];
result.push({
...obj2Nodes[i],
'irb': {
...reObj1Nodes
}
})
}
}
}
console.log(result)

How to make payload response return data into different format?

I need to change the structure of the payload response from the REST call on the frontend. Right now the api returns the data in the following format:
[
{
"row": [
{
"name": "Desc",
"value": "7777 - Florida Hurricane"
},
{
"name": "DSTR_NR",
"value": "7777"
}
]
},
{
"row": [
{
"name": "Desc",
"value": "7172 - Virginia Severe Storm(s)"
},
{
"name": "DSTR_NR",
"value": "7172"
}
]
}
]
This is what I have so far but it does not give me the data in the proper format:
let result = payload.reduce(function(res, obj) {
let temp = obj.row.map(function(o) {
return Object.assign({}, o);
});
return res.concat(temp);
},[])
return result;
// instead, this returns the data in the following way:
{name: "Desc", value: "7777 - Florida Hurricane"}
{name: "DSTR_NR", value: "7777"}
How can I make the payload response structure into the following desired format?
{name: "7777 - Florida Hurricane", value: "7777"}
{name: "7172 - Virginia Severe Storm(s)", value: "7172"}
for name, I only want the value for Desc and
for value, I only want the value for DSTR_NR
I think that's what you're looking for:
const getDesiredFormat = response => response.map(data => {
const row = data['row']
return {
name: row[0].value,
value: row[1].value
}
}, [])
This should be easy.
Here you go..
var data = [
{
"row": [
{
"name": "Desc",
"value": "7777 - Florida Hurricane"
},
{
"name": "DSTR_NR",
"value": "7777"
}
]
},
{
"row": [
{
"name": "Desc",
"value": "7172 - Virginia Severe Storm(s)"
},
{
"name": "DSTR_NR",
"value": "7172"
}
]
}
].reduce((arr, value)=>{
var row = value.row;
arr.push({name:row.find(x=> x.name =="Desc").value, value:row.find(x=> x.name =="DSTR_NR").value})
return arr
},[])
console.log(data)
you can use map
var data = [{
"row": [{
"name": "Desc",
"value": "7777 - Florida Hurricane"
},
{
"name": "DSTR_NR",
"value": "7777"
}
]
},
{
"row": [{
"name": "Desc",
"value": "7172 - Virginia Severe Storm(s)"
},
{
"name": "DSTR_NR",
"value": "7172"
}
]
}
];
console.log(data.map(i => {
if (i.row.length) {
var val1 = i.row.find(f => f.name.toLowerCase() === "desc");
var val2 = i.row.find(f => f.name.toLowerCase() === "dstr_nr");
if (val1 && val2) {
return {
name: val1.value,
value: val2.value
};
}
}
}))
This should handle your problem
result = data.reduce(function(res, obj) {
let temp = obj.row.reduce(function(tempObj, element) {
if(element.name === "Desc"){tempObj.name = element.value}
else tempObj.value = element.value
return tempObj
}, {});
return res.concat(temp);
},[])

Javascript nested .map() returning multiple arrays

Given that I have a JSON structure like this:
{
"firstData": [{
"secondData": [{
"thirdData": [{
"value": "whatever"
}]
}]
}]
}
And I need to map from thirdData value === "whatever"
So I am doing
const result = firstData.map(first => {
return first.secondData.map(second => {
return second.thirdData.map(third => {
return third.value === 'whatever';
});
});
});
And this works somewhat fine, but the result is a another deeply nested array (like [ [ [ {results..} ] ] ]). I know I can flatten this to a single array by other means, but I feel like I am miss using .map(). How can I modify this result to a single array that contains the values of thirdData where the value is what ever I want?
The desired result for this would be a single array of thirdData objects:
[{ value: 'whatever'}, ... {n}]
You can use Array#reduce for reducing into a single value(in this case single array) and Array#forEach for iterating over the nested array.
const data = {
"firstData": [{
"secondData": [{
"thirdData": [{
"value": "whatever"
}]
}]
}]
}
const result = data.firstData.reduce((arr, first) => {
// iterate over the second level array
first.secondData.forEach(second => {
// iterate over the third level array
second.thirdData.forEach(third => {
// push the value into the result array,
// change here, in case you want the value
//arr.push(third.value === 'whatever');
// in case you need the object then do it like
if(third.value === 'whatever') arr.push(third);
});
});
// return the array reference for the next iteration
return arr;
// set the initial value as an array for the result
}, []);
console.log(result);
If you want a flat result, this isn't a use case for map. The simple solution is just to use an array you close over and push to:
const result = [];
firstData.forEach(first => {
return first.secondData.forEach(second => {
result.push(...second.thirdData.filter(third => third.value === 'whatever'));
});
});
Live Example with a slight extension to your minimal provided data:
const data = {
"firstData": [{
"secondData": [{
"thirdData": [{
"value": "whatever",
"label": "third #1.1"
},
{
"value": "whatever",
"label": "third #1.2"
},
{
"value": "unrelated",
"label": "unrelated"
}
]
}]
},
{
"secondData": [{
"thirdData": [{
"value": "another unrelated"
},
{
"value": "whatever",
"label": "third #2"
}
]
}]
}
]
};
const result = [];
data.firstData.forEach(first => {
return first.secondData.forEach(second => {
result.push(...second.thirdData.filter(third => third.value === 'whatever'));
});
});
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
Note the filter on the thirdData and using spread notation to push that data into result.
That assumes you want the entry from thirdData that has .value === 'whatever' rather than a true/false. If you want the true/false instead, change that filter to map.
Or the for-of equivalent:
const result = [];
for (const first of firstData) {
for (const second of first.secondData) {
result.push(...second.thirdData.filter(third => third.value === 'whatever'));
}
}
Live Example with a slight extension to your minimal provided data:
const data = {
"firstData": [{
"secondData": [{
"thirdData": [{
"value": "whatever",
"label": "third #1.1"
},
{
"value": "whatever",
"label": "third #1.2"
},
{
"value": "unrelated",
"label": "unrelated"
}
]
}]
},
{
"secondData": [{
"thirdData": [{
"value": "another unrelated"
},
{
"value": "whatever",
"label": "third #2"
}
]
}]
}
]
};
const result = [];
for (const first of data.firstData) {
for (const second of first.secondData) {
result.push(...second.thirdData.filter(third => third.value === 'whatever'));
}
}
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
(Same note about filter/map.)
As with all array operations, you can shoehorn this into reduce, and I guarantee you you'll get answers primarily using reduce, but there's no good reason to use reduce here.
const result = firstData.reduce((result, first) => {
return first.secondData.reduce((result, second) => {
result.push(...second.thirdData.filter(third => third.value === 'whatever'));
return result;
}, result);
}, []);
Again, though, there's no good reason for that. It's just more complicated.
Live Example with a slight extension to your minimal provided data:
const data = {
"firstData": [{
"secondData": [{
"thirdData": [{
"value": "whatever",
"label": "third #1.1"
},
{
"value": "whatever",
"label": "third #1.2"
},
{
"value": "unrelated",
"label": "unrelated"
}
]
}]
},
{
"secondData": [{
"thirdData": [{
"value": "another unrelated"
},
{
"value": "whatever",
"label": "third #2"
}
]
}]
}
]
};
const result = data.firstData.reduce((result, first) => {
return first.secondData.reduce((result, second) => {
result.push(...second.thirdData.filter(third => third.value === 'whatever'));
return result;
}, result);
}, []);
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
(Same note about filter/map.)

Remove duplicate array from response comparing attribute value

I want to remove a duplicate array from the response on the basis of the attribute value. If the attribute_value data match with other array attribute value then other should be removed.
The logic is very simple. check duplicate attribute_value in each array and remove duplicate array and return
In response. now you can see the attribute value = 1 is thrice
and attribute value = 2 is twice
How do i compare and remove whole array if I see attribute value duplicate?
I tried with filter method which seems not working. Please help.
for(var j=0; j<social_post_link.length; j++){
newFilterarray = social_post_link[j].activity_attributes[0].attribute_value.filter(function(item, index) {
if (social_post_link[j].activity_attributes[0].attribute_value.indexOf(item) == index){
return social_post_link;
}
});
}
Response
[
{
"id": "484822",
"activity_attributes": [
{
"id": "868117",
"activity_id": "484822",
"attribute_name": "position",
"attribute_value": "1",
}
]
},
{
"id": "484884",
"activity_attributes": [
{
"id": "868175",
"activity_id": "484884",
"attribute_name": "position",
"attribute_value": "1",
}
]
},
{
"id": "484888",
"activity_attributes": [
{
"id": "868182",
"activity_id": "484888",
"attribute_name": "position",
"attribute_value": "1",
}
]
},
{
"id": "484823",
"activity_attributes": [
{
"id": "868120",
"activity_id": "484823",
"attribute_name": "position",
"attribute_value": "2",
}
]
},
{
"id": "484975",
"activity_attributes": [
{
"id": "868344",
"attribute_name": "position",
"attribute_value": "2",
}
]
},
{
"id": "484891",
"activity_attributes": [
{
"id": "868189",
"attribute_name": "position",
"attribute_value": "3",
}
]
},
{
"id": "484903",
"activity_attributes": [
{
"id": "868200",
"attribute_name": "position",
"attribute_value": "4",
},
]
}
]
Desired output
[
{
"id": "484822",
"activity_attributes": [
{
"id": "868117",
"activity_id": "484822",
"attribute_name": "position",
"attribute_value": "1",
}
]
},
{
"id": "484823",
"activity_attributes": [
{
"id": "868120",
"activity_id": "484823",
"attribute_name": "position",
"attribute_value": "2",
}
]
},
{
"id": "484891",
"activity_attributes": [
{
"id": "868189",
"attribute_name": "position",
"attribute_value": "3",
}
]
},
{
"id": "484903",
"activity_attributes": [
{
"id": "868200",
"attribute_name": "position",
"attribute_value": "4",
},
]
}
]
You can probably use the lodash utility uniqBy,
where iteratee is a function that returns the value you want to compare against.
In your case, it would probably look like the following:
const uniqueLinks = _.uniqBy(social_post_link, item =>
item.activity_attributes[0].attribute_value
)
Edit:
Here is a vanilla JS function that will accomplish the same.
const filterByIteratee = (array, iteratee) => {
// Empty object to store attributes as we encounter them
const previousAttributeNames = {
}
return array.filter(item => {
// Get the right value
const itemValue = iteratee(item)
// Check if we have already stored this item
if (previousAttributeNames.hasOwnProperty(itemValue)) return false
else {
// Store the item so next time we encounter it we filter it out
previousAttributeNames[itemValue] = true
return true
}
})
}
It will loop through an array, store its identifier by some function, and return only the first instance of each item.
Use it the same way:
const uniqueLinks = filterByIteratee(social_post_link, item =>
item.activity_attributes[0].attribute_value
)
This is probably not the best performing solution. but it works for your requirements.
var resultArray = [];
for (var i = 0; i < social_post_link.length; i++) {
var currentSocialLink = social_post_link[i];
for (var j = 0; j < currentSocialLink.activity_attributes.length; j++) {
if (!resultArray.some(val =>
val.activity_attributes.some(activity =>
activity.attribute_value === currentSocialLink.activity_attributes[j].attribute_value))) {
resultArray.push(currentSocialLink);
}
}
}
function removeDuplicates(myArr, prop) { // removes duplicate objects from array
return myArr.filter((obj, pos, arr) => {
return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;
});
};
I found this function not too long ago which removes duplicate objects from an array. Pass it the array and the property you wish to not be duplicated.

Group and count values in an array

I have an array with objects, like the following.
b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
I want to count how many issues have status close, and how many have backlog. I'd like to save the count in a new array as follows.
a = [
{Name: 'Backlog', count: 1},
{Name: 'close', count: 2}
];
I have tried the following.
b.issues.forEach(function(i) {
var statusName = i.fields.status.name;
if (statusName in a.Name) {
a.count = +1;
} else {
a.push({
Name: statusName,
count: 1
});
}
});
That however doesn't seem to be working. How should I implement this?
This is a perfect opportunity to use Array#reduce. That function will take a function that is applied to all elements of the array in order and can be used to accumulate a value. We can use it to accumulate an object with the various counts in it.
To make things easy, we track the counts in an object as simply {name: count, otherName: otherCount}. For every element, we check if we already have an entry for name. If not, create one with count 0. Otherwise, increment the count. After the reduce, we can map the array of keys, stored as keys of the object, to be in the format described in the question. See below.
var b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
var counts = b.issues.reduce((p, c) => {
var name = c.fields.status.name;
if (!p.hasOwnProperty(name)) {
p[name] = 0;
}
p[name]++;
return p;
}, {});
console.log(counts);
var countsExtended = Object.keys(counts).map(k => {
return {name: k, count: counts[k]}; });
console.log(countsExtended);
.as-console-wrapper {
max-height: 100% !important;
}
Notes.
Array#reduce does not modify the original array.
You can easily modify the function passed to reduce to for example not distinguish between Backlog and backlog by changing
var name = c.fields.status.name;
into
var name = c.fields.status.name.toLowerCase();
for example. More advanced functionality can also easily be implemented.
Using ES6 Arrow functions you can do it with minimum syntax
var b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
var countOfBackLog = b.issues.filter(x => {
return x.fields.status.name === "Backlog"
}).length
var countOfClose = b.issues.filter(x => {
return x.fields.status.name === "close"
}).length
a =[{Name: 'Backlog', count : countOfBackLog}, {Name: 'close', count : countOfClose}]
More about arrow functions here
You can write like this. It is dynamic.
var a = {};
for(var key in b["issues"]){
if(!a.hasOwnProperty(b["issues"][key].fields.status.name)){
a[b["issues"][key].fields.status.name] = 1;
}else{
a[b["issues"][key].fields.status.name] = a[b["issues"][key].fields.status.name]+1;
}
}
var c = [];
for(var key1 in a){
c.push({
name : key1,
count : a[key1]
});
}
Something like this should do the trick. Simply iterate over your data, keep 2 counters with the number of each type of issue, and create the data format you want in the end. Try it live on jsfiddle.
var b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
var data = [];
for(var issue of b.issues){
var entryFound = false;
var tempObj = {
name: issue.fields.status.name,
count: 1
};
for(var item of data){
if(item.name === tempObj.name){
item.count++;
entryFound = true;
break;
}
}
if(!entryFound){
data.push(tempObj);
}
}
console.log(data);

Categories

Resources