How can I find and update values in an array of objects?
I have an array of objects. I want to find by some field, and then to change it:
var item = {...}
var items = [{id:2}, {id:2}, {id:2}];
var foundItem = items.find(x => x.id == item.id);
foundItem = item;
I want it to change the original object. How? (I don't care if it will be in Lodash too.)
Solution 1:
You can use findIndex to find the index in the array of the object and replace it as required:
var item = {...}
var items = [{id:2}, {id:2}, {id:2}];
var foundIndex = items.findIndex(x => x.id == item.id);
items[foundIndex] = item;
This assumes unique IDs. If your IDs are duplicated (as in your example), it's probably better if you use forEach:
items.forEach((element, index) => {
if(element.id === item.id) {
items[index] = item;
}
});
Solution 2:
My best approach is:
var item = {...}
var items = [{id:2}, {id:2}, {id:2}];
items[items.findIndex(el => el.id === item.id)] = item;
Reference for findIndex
And in case you don't want to replace with new object, but instead to copy the fields of item
, you can use Object.assign
:
Object.assign(items[items.findIndex(el => el.id === item.id)], item)
as an alternative with .map()
:
Object.assign(items, items.map(el => el.id === item.id? item : el))
Functional approach:
Don't modify the array, use a new one, so you don't generate side effects
const updatedItems = items.map(el => el.id === item.id ? item : el)
Note
Properly used, references to objects are not lost, so you could even use the original object reference, instead of creating new ones.
const myArr = [{ id: 1 }, { id: 2 }, { id: 9 }];
const [a, b, c] = myArr;
// modify original reference will change object in the array
a.color = 'green';
console.log(myArr[0].color); // outputs 'green'
This issue usually happens when consuming lists from database and then mapping the list to generate HTML content which will modify the elements of the list, and then we need to update the list and send it back to database as a list.
Good news is, references are kept, so you could organize your code to get advantage of it, and think about a list
as an Object with identities for free, which are integers from 0 to length -1
. So every time you access any property of your Object, do it as list[i]
, and you don't lose reference, and original object is changed. Keep in mind that this is useful when your source of truth is only one (the Object created), and your app is always consistently consuming the same Object (not fetching several times from database and assigning it to list
along the lifespan of the component).
Bad news is that the architecture is wrong, and you should receive an object by ids (dictionary) if this is what you need, something like
{
1232: { id: 1232, ...},
asdf234asf: { id: 'asdf234asf', ...},
...
}
This way, you don't search in arrays, which is resource consuming. You "just access by key in the object", which is instant and performant.
Solution 3:
One-liner using spread operator.
const updatedData = originalData.map(x => (x.id === id ? { ...x, updatedField: 1 } : x));
Solution 4:
An other approach is to use splice.
The
splice()
method changes the contents of an array by removing or replacing existing elements and/or adding new elements in place.
N.B : In case you're working with reactive frameworks, it will update the "view", your array "knowing" you've updated it.
Answer :
var item = {...}
var items = [{id:2}, {id:2}, {id:2}];
let foundIndex = items.findIndex(element => element.id === item.id)
items.splice(foundIndex, 1, item)
And in case you want to only change a value of an item, you can use find function :
// Retrieve item and assign ref to updatedItem
let updatedItem = items.find((element) => { return element.id === item.id })
// Modify object property
updatedItem.aProp = ds.aProp