javascript - ¿Cómo puedo encontrar y actualizar valores en un arreglo de objetos?
Tengo un array de objetos. Quiero buscar por algún campo y luego cambiarlo:
var item = {...}
var items = [{id:2}, {id:2}, {id:2}];
var foundItem = items.find(x => x.id == item.id);
foundItem = item;
Quiero que cambie el objeto original. ¿Cómo? (No me importa si también estará en Lodash.)
Respuesta #1
Puedes usar findIndex para encontrar el índice en el arreglo del objeto y reemplazarlo según sea necesario:
var item = {...}
var items = [{id:2}, {id:2}, {id:2}];
var foundIndex = items.findIndex(x => x.id == item.id);
items[foundIndex] = item;
Esto supone IDs únicos. Si tus IDs están duplicados (como en tu ejemplo), probablemente sea mejor que uses forEach:
items.forEach((element, index) => {
if(element.id === item.id) {
items[index] = item;
}
});
Respuesta #2
Mi mejor enfoque es:
var item = {...}
var items = [{id:2}, {id:2}, {id:2}];
items[items.findIndex(el => el.id === item.id)] = item;
Referencia para findIndex
Y en caso de que no quieras reemplazar con un nuevo objeto, sino copiar los campos de item, puedes usar Object.assign:
Object.assign(items[items.findIndex(el => el.id === item.id)], item)como una alternativa con .map():
Object.assign(items, items.map(el => el.id === item.id? item : el))Enfoque funcional:
No modifiques el array, usa uno nuevo, para que no generes efectos secundarios
const updatedItems = items.map(el => el.id === item.id ? item : el)
Nota
Usadas correctamente, las referencias a objetos no se pierden, por lo que incluso podrías usar la referencia al objeto original, en lugar de crear nuevas.
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'
Este problema generalmente ocurre al consumir listas de la base de datos y luego mapear la lista para generar contenido HTML que modificará los elementos de la lista, y luego necesitamos actualizar la lista y enviarla de nuevo a la base de datos como una lista.
La buena noticia es que se mantienen las referencias, así que podrías organizar tu código para aprovecharlo, y pensar en una list como un Objeto con identidades gratis, que son enteros desde 0 hasta length -1. Así que cada vez que accedas a cualquier propiedad de tu Objeto, hazlo como list[i], y no pierdes la referencia, y el objeto original se modifica. Ten en cuenta que esto es útil cuando tu fuente de verdad es solo una (el Objeto creado), y tu aplicación siempre está consumiendo de manera consistente el mismo Objeto (no recuperando varias veces de la base de datos y asignándolo a list a lo largo de la vida del componente).
La mala noticia es que la arquitectura está mal, y deberías recibir un objeto por ids (diccionario) si esto es lo que necesitas, algo así
{
1232: { id: 1232, ...},
asdf234asf: { id: 'asdf234asf', ...},
...
}
De esta manera, no buscas en arrays, lo cual consume recursos. Simplemente "accedes por clave en el objeto", lo cual es instantáneo y eficiente.
Respuesta #3
Una línea usando el operador de propagación.
const updatedData = originalData.map(x => (x.id === id ? { ...x, updatedField: 1 } : x));
Respuesta #4
Otro enfoque es usar splice.
El método
splice()cambia el contenido de un arreglo eliminando o reemplazando elementos existentes y/o agregando nuevos elementos en su lugar.
N.B : En caso de que estés trabajando con frameworks reactivos, actualizará la "vista", tu arreglo "sabiendo" que lo has actualizado.
Respuesta :
var item = {...}
var items = [{id:2}, {id:2}, {id:2}];
let foundIndex = items.findIndex(element => element.id === item.id)
items.splice(foundIndex, 1, item)
Y en caso de que solo quieras cambiar el valor de un elemento, puedes usar la función find:
// Retrieve item and assign ref to updatedItem
let updatedItem = items.find((element) => { return element.id === item.id })
// Modify object property
updatedItem.aProp = ds.aProp
Respuesta #5
Dado un objeto modificado y un arreglo:
const item = {...}
let items = [{id:2}, {id:3}, {id:4}];
Actualiza el array con el nuevo objeto iterando sobre el array:
items = items.map(x => (x.id === item.id) ? item : x)
