Update only a single key in a javascript object with map - javascript

I want to update my thumbnail key in my object.
products :[
{
id: 1,
name: "sth,
thumb : 'abc.jpg'
}
];
I want to update the products.thumb of all the objects in that array like thumb: 'server/abc.jpg
searchedProducts = products.map(product => {
return Object.assign({},
product,
product.thumb = product.thumb ? 'server'+product.thumb : '')
});
Current output
[{
0: 's,
1: 'e',
3: 'r',
4: 'v',
5: 'e',
id: 1,
thumb :'server/abc.jpg'
}]

With spread syntax:
const products = [
{
id: 1,
name: 'sth',
thumb : 'abc.jpg'
}
];
searchedProducts = products.map(product => {
const thumb = product.thumb ? 'server/' + product.thumb : '';
return { ...product, thumb };
});
console.log(searchedProducts);

You probably meant to use Object.assign like so:
const products = [
{
id: 1,
name: 'sth',
thumb : 'abc.jpg'
}
]
const searchedProducts = products.map(product => {
return Object.assign({}, product, {
thumb: product.thumb ? 'server/' + product.thumb : ''
})
})
console.log(searchedProducts)
In the above snippet I'm merging:
An empty object.
With the currently iterated product object.
With another object containing the computed thumb key.

Why would this not work for you?
const products = [
{
id: 1,
name: 'sth',
thumb : 'abc.jpg'
},
{
id: 2,
name: 'sth',
thumb : 'def.jpg'
}
];
// Non mutating
let copy = JSON.parse(JSON.stringify(products));
copy.forEach(product => {
product.thumb = product.thumb ? 'copyserver/'+product.thumb : '';
});
console.log(copy);
// Mutating
products.forEach(product => {
product.thumb = product.thumb ? 'server/'+product.thumb : '';
});
console.log(products);

You could destructure and get the thumb property and keep the remaining properties in rest. This way you can keep the remaining properties as they are:
const products = [{
id: 1,
name: "sth",
thumb: 'abc.jpg'
},
{
id: 2,
name: "sth2",
thumb: 'def.jpg'
}
];
const newProducts = products
.map(({thumb, ...rest}) => ({ thumb: thumb ? `server/${thumb}` : ``, ...rest }));
console.log(newProducts)

You could also do this using reduce, initialising your start with an empty array,
const result = products.reduce((prev, next) => {
next.thumb = `server/${next.thumb}`;
prev.push(next);
return prev;
}, []);
console.log(result);
Just another way of doing it other than map.

You can use destructing assignment with .map to modify all thumb properties.
See working example below:
const products = [{id:1,name:"sth",thumb:"abc.jpg"},{id:2,name:"byt",thumb:"def.jpg"},{id:3,name:"mth"}],
res = products.map(({thumb, ...others}) => ({...others, "thumb": thumb ? "server/" + thumb:''}));
console.log(res);

Related

How to delete an item from my Reducer Object?

I have an object in my reducer like this :
clientData : {
1080 : [{ID : 1111,name : 'John'},{ID : 2222,name : 'Stan'},],
1090 : [{ID : 3333,name : 'Adam'},{ID : 4444,name : 'Alan'},]
}
And I want to be able to delete an item (for example Stan with 2222 ID's)
The problem that is I don't have the key of my property (1080), and I don't have any idea how to achieve it.
I've tried the Object.values(object1) but it convert my object to array and I lost all my architecture.
Have you an idea please ?
Removing from existing objects might not be good, you can use Object.entries and filter to remove id.
If you want to change existing pass data to reducer
const data = {
1080: [
{ ID: 1111, name: "John" },
{ ID: 2222, name: "Stan" },
],
1090: [
{ ID: 3333, name: "Adam" },
{ ID: 4444, name: "Alan" },
],
};
const remove = (id, data) => {
const entries = Object.entries(data);
return entries.reduce((acc, [key, value]) => {
const newValue = value.filter((item) => item.ID !== id);
acc[key] = newValue;
return acc;
// return { ...acc, [key]: newValue };
}, {}); // for updating existing data here
};
console.log(remove(2222, data))

How to update the value into a nested array of objects if value for specific key is same?

let data = [
{"name":"Dhanush","createdAt":"2021/01/13 16:57:53","songs":[]},
{"name":"Dharma","createdAt":"2021/01/13 17:02:47","songs":[]},
{"name":"Sachin","createdAt":"2021/01/13 17:30:45","songs":[]}
]
let name = "Dhanush"
let song = {
'id':1,
'duration': '5 mins',
'name': 'Bingo'
}
Here I need to loop the data array and check if data.name === name , if it s true I need to push the song object to the songs array inside the data.
this means
data = data.map(val => val.name === name ? val.songs = [...val.songs,song] : val.songs)
I tried like this. but it doesn't work.
Your help is much appreciated.
Thanks
You are not returning val when using map method.
let data = [
{ name: 'Dhanush', createdAt: '2021/01/13 16:57:53', songs: [] },
{ name: 'Dharma', createdAt: '2021/01/13 17:02:47', songs: [] },
{ name: 'Sachin', createdAt: '2021/01/13 17:30:45', songs: [] },
];
const name = 'Dhanush';
const song = {
id: 1,
duration: '5 mins',
name: 'Bingo',
};
data = data.map(
(val) => (
val.name === name ? (val.songs = [...val.songs, song]) : val.songs, val
)
);
console.log(data);

Object.entries alternative transforming array of object into strings

I tried to print "person[0].name: a" and "person[1].name: b" and so on, based on this person array of object:
I used object entries twice, any other way I can make the loop more efficient?
const person = [{
name: 'a',
}, {
name: 'b'
}]
Object.entries(person).forEach(([key, value]) => {
Object.entries(value).forEach(([key2, value2]) => {
console.log(`person[${key}].${key2}`, ':', value2)
})
})
You could take a recursive approach and hand over the parent path.
const
show = (object, parent) => {
const wrap = Array.isArray(object) ? v => `[${v}]` : v => `.${v}`;
Object.entries(object).forEach(([k, v]) => {
if (v && typeof v === 'object') show(v, parent + wrap(k));
else console.log(parent + wrap(k), v);
});
},
person = [{ name: 'a' }, { name: 'b' }];
show(person, 'person');
You don't really need the first call. person is already an Array.
const person = [{
name: 'a',
}, {
name: 'b'
}]
person.forEach((value, key) => {
Object.entries(value).forEach(([key2, value2]) => {
console.log(`person[${key}].${key2}`, ':', value2)
})
})
Just in case forEach is for side effects. If you want to create another array with transformed values you better use map/flatMap instead.
const person = [{
name: 'a',
}, {
name: 'b'
}]
const transformed = person.flatMap((value, key) => {
return Object.entries(value).map(([key2, value2]) => `person[${key}].${key2}:${value2}`)
})
console.log(transformed)
You can also try something like this, with only one forEach() loop
const person = [{
name: 'a',
},{
name: 'b'
}];
person.forEach((el,i) => {
let prop = Object.keys(el).toString();
console.log(`person[${i}].${prop}`, ':', el[prop])
});

Javascript concat and prefix or rename props

I have two arrays that I am concatinating.
However each of these arrays has same property name I want to leave by adding prefix to each.
Array A(aData) looks like
[
{
id: 1,
title: `title`
code: '34x'
},
...
]
Array B(bData) looke like:
[
{
id: 1
prop: 3,
otherporp: `prop`
code: 'hi67'
},
...
]
In order to combine the arrays I am doing concat and reduce to get only matching id's
const data: any = aData.concat(bData).reduce((acc, x) => {
acc[x.id] = Object.assign(acc[x.id] || {}, x);
return acc;
}, {});
return Object.values(data);
But the issue is that my bData code props getting lost.
Is there any way I can rename the code from aData to say aCode and the code from bData to bCode ?
You can create a new array from both of your array with updated key value aCode and bCode instead of code key. Then concat both of these arrays and merge them on the id key.
const arrA = [{ id: 1, title: `title`, code: '34x' }],
arrB = [{ id: 1, prop: 3, otherporp: `prop`, code: 'hi67'}];
const newArrA = arrA.map(({code, ...rest}) => ({...rest, aCode : code}));
const newArrB = arrB.map(({code, ...rest}) => ({...rest, bCode : code}))
const merged = Object.values([].concat(newArrA, newArrB).reduce((r,o) => {
r[o.id] = r[o.id] || Object.assign({},o);
Object.assign(r[o.id], o);
return r;
}, {}));
console.log(merged);
var arrA = [{
id: 1,
title: `title`,
code: '34x'
}],
arrB = [{
id: 1,
prop: 3,
otherporp: `prop`,
code: 'hi67'
}];
let newArrA = arrA.map(({
code,
...rest
}) => ({ ...rest,
aCode: code
}));
const newArrB = arrB.map(({
code,
...rest
}) => ({ ...rest,
bCode: code
}));
result = newArrA.map(function(v) {
var ret;
$.each(newArrB, function(k, v2) {
if (v2.id === v.id) {
ret = $.extend({}, v2, v);
return false;
}
});
return ret;
});
console.log(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Count elements that have the same value for a specific property and put the result in an array of objects

Using Array.reduce, I am trying to count the elements that have the same value for a specific property. I want to put the result in an array of objects containing a property for the value of the grouped by property and another one for the count. How can I do this easily in javascript ?
const CATEGORY = {
STRATEGY: 'STRATEGY',
CONTENT: 'CONTENT',
ADVERTISING: 'ADVERTISING',
MEASURMENT: 'MEASURMENT'
}
const lessons = [
{
title: 'ohoho',
category: CATEGORY.STRATEGY
}, {
title: 'hihihi',
category: CATEGORY.CONTENT
}, {
title: 'hello',
category: CATEGORY.CONTENT
}
]
let categoryLessonCount = lessons.reduce(function (acc, lesson) {
acc[lesson.category] ? acc[lesson.category]++ : acc[lesson.category] = 1
return acc
}, {})
console.log(categoryLessonCount[CATEGORY.STRATEGY])
console.log(categoryLessonCount[CATEGORY.CONTENT])
Actual categoryLessonCount value :
Object
{
STRATEGY: 1,
CONTENT: 2
}
Wanted categoryLessonCount value :
Array
[
{
title: 'STRATEGY',
count: 1
}, {
title: 'CONTENT',
count: 2
}
]
You already got the what you want just transform it into an array
const CATEGORY = {
STRATEGY: 'STRATEGY',
CONTENT: 'CONTENT',
ADVERTISING: 'ADVERTISING',
MEASURMENT: 'MEASURMENT'
}
const lessons = [{
title: 'ohoho',
category: CATEGORY.STRATEGY
}, {
title: 'hihihi',
category: CATEGORY.CONTENT
}, {
title: 'hello',
category: CATEGORY.CONTENT
}]
let count = lessons.reduce(function(acc, lesson) {
acc[lesson.category] ? acc[lesson.category] ++ : acc[lesson.category] = 1
return acc
}, {})
// transform count into what you want
let categoryLessonCount = [];
for (let cat in count) {
categoryLessonCount.push({
'title': cat,
'count': count[cat]
});
}
console.log(categoryLessonCount)
Something like this should work:
let categoryLessonCount = lessons.reduce(function(acc, lesson) {
let found = false
for (const item of acc) {
if (item.title === lesson.category) {
item.count++
found = true
}
}
if (!found) {
acc.push({
title: lesson.category,
count: 1
})
}
return acc
}, [])
Your main issue is that your accumulating an object but expecting an array (note the final argument to reduce).
Short solution using Object.keys and Array.prototype.map functions:
...
let categoryLessonCount = lessons.reduce(function (acc, lesson) {
acc[lesson.category] ? acc[lesson.category]++ : acc[lesson.category] = 1
return acc
}, {})
let counts = Object.keys(categoryLessonCount).map(
(k) => ({title: k, count: categoryLessonCount[k]})
)
console.log(counts);

Categories

Resources