Update if exists or add new element to array of objects - elegant way in javascript + lodash Update if exists or add new element to array of objects - elegant way in javascript + lodash arrays arrays

Update if exists or add new element to array of objects - elegant way in javascript + lodash


In your first approach, no need for Lodash thanks to findIndex():

function upsert(array, item) { // (1)  const i = array.findIndex(_item => _item.id === item.id);  if (i > -1) array[i] = item; // (2)  else array.push(item);}

Example:

const array = [  {id: 0, name: 'Apple', description: 'fruit'},  {id: 1, name: 'Banana', description: 'fruit'},  {id: 2, name: 'Tomato', description: 'vegetable'}];upsert(array, {id: 2, name: 'Tomato', description: 'fruit'})console.log(array);/* =>[  {id: 0, name: 'Apple', description: 'fruit'},  {id: 1, name: 'Banana', description: 'fruit'},  {id: 2, name: 'Tomato', description: 'fruit'}]*/upsert(array, {id: 3, name: 'Cucumber', description: 'vegetable'})console.log(array);/* =>[  {id: 0, name: 'Apple', description: 'fruit'},  {id: 1, name: 'Banana', description: 'fruit'},  {id: 2, name: 'Tomato', description: 'fruit'},  {id: 3, name: 'Cucumber', description: 'vegetable'}]*/

(1) other possible names: addOrReplace(), addOrUpdate(), appendOrUpdate(), insertOrUpdate()...

(2) can also be done with array.splice(i, 1, item)

Note that this approach is "mutable" (vs "immutable"): it means instead of returning a new array (without touching the original array), it modifies directly the original array.


You can use an object instead of an array:

var hash = {  '1': {uid: 1, name: "bla", description: "cucu"},  '2': {uid: 2, name: "smth else", description: "cucarecu"}};

The keys are the uids. Now your function addOrReplace is simple like this:

function addOrReplace(hash, object) {    hash[object.uid] = object;}

UPDATE

It's also possible to use an object as an index in addition to the array.
This way you've got fast lookups and also a working array:

var arr = [],    arrIndex = {};addOrReplace({uid: 1, name: "bla", description: "cucu"});addOrReplace({uid: 2, name: "smth else", description: "cucarecu"});addOrReplace({uid: 1, name: "bli", description: "cici"});function addOrReplace(object) {    var index = arrIndex[object.uid];    if(index === undefined) {        index = arr.length;        arrIndex[object.uid] = index;    }    arr[index] = object;}

Take a look at the jsfiddle-demo (an object-oriented solution you'll find here)


I personally do not like solutions that modify the original array/object, so this is what I did:

function addOrReplaceBy(arr = [], predicate, getItem) {  const index = _.findIndex(arr, predicate);  return index === -1    ? [...arr, getItem()]    : [      ...arr.slice(0, index),      getItem(arr[index]),      ...arr.slice(index + 1)    ];}

And you would use it like:

var stuff = [  { id: 1 },  { id: 2 },  { id: 3 },  { id: 4 },];var foo = { id: 2, foo: "bar" };stuff = addOrReplaceBy(  stuff,  { id: foo.id },  (elem) => ({    ...elem,    ...foo  }));

What I decided to do was to make it more flexible:

  1. By using lodash -> _.findIndex(), the predicate can be multiple things
  2. By passing a callback getItem(), you can decide whether to fully replace the item or do some modifications, as I did in my example.

Note: this solution contains some ES6 features such as destructuring, arrow functions, among others.