0

I would like to know how to update an array of objects list using javascript.

How to update the objList with the newObjList by matching the id and name. If the id and name matches, then update the objList nested array object.

var result = updateObj(objList, newObjList);
console.log(result);

function updateObj(list, newObjList){
  var flatarr = list.map(e=>Object.entries(e).map(([k, val]) => val)).flat(3);
  var filterService =  newObjList.filter(e=>e.name=="service");
  //got stuck
}

var newObjList=[{
    "id": "service",
    "name": "bank",
    "amount": 2000
},{
    "id": "service",
    "name": "credit",
    "amount": 5000
}]


var objList=[
{
  "btob": [{
    "id": "service",
    "name": "bank",
    "amount": 1000
  },{
    "id": "fund",
    "name": "bank",
    "amount": 2000
  },{
    "id": "others",
    "name": "bank",
    "amount": 5000
   }]
},{
 "ctob":[{
    "id": "service",
    "name": "credit",
    "amount": 1000,
    "rate": 0.4
  },{
    "id": "fund",
    "name": "credit",
    "amount": 3000,
    "rate": 0.2
  },{
    "id": "others",
    "name": "credit",
    "amount": 4000,
    "rate": 0.6
   }]
  }]
}]

Expected Output:

var result=[
{
  "btob": [{
    "id": "service",
    "name": "bank",
    "amount": 2000
  },{
    "id": "fund",
    "name": "bank",
    "amount": 2000
  },{
    "id": "others",
    "name": "bank",
    "amount": 5000
   }]
},{
 "ctob":[{
    "id": "service",
    "name": "credit",
    "amount": 5000,
    "rate": 0.4
  },{
    "id": "fund",
    "name": "credit",
    "amount": 3000,
    "rate": 0.2
  },{
    "id": "others",
    "name": "credit",
    "amount": 4000,
    "rate": 0.6
   }]
  }]
}]

buræquete
  • 14,226
  • 4
  • 44
  • 89
Senthil
  • 961
  • 1
  • 8
  • 21
  • Possible duplicate of [Comparing Arrays of Objects in JavaScript](https://stackoverflow.com/questions/27030/comparing-arrays-of-objects-in-javascript) – Charlie Jul 24 '19 at 04:02

4 Answers4

0

You can do the following;

var flatList = objList.flatMap(obj => obj["btob"] || obj["ctob"]);
newObjList.forEach(newObj => flatList
       .filter(obj => obj.id == newObj.id && obj.name == newObj.name)
       .forEach(obj => Object.keys(newObj).forEach(key => obj[key] = newObj[key])));

As you can see the code is very clean & readable, first flattening the targeted objList to make it more easily accessible, then just iterate newObjList, find the targeted objects in the flattened list, and update them. This update logic is done via Object.keys() because OP wants object update without any hardcoded keys in the process.

You can see it in action in below snippet;

var newObjList = [{
  "id": "service",
  "name": "bank",
  "amount": 2000
}, {
  "id": "service",
  "name": "credit",
  "amount": 5000
}];

var objList = [{
  "btob": [{
    "id": "service",
    "name": "bank",
    "amount": 1000
  }, {
    "id": "fund",
    "name": "bank",
    "amount": 2000
  }, {
    "id": "others",
    "name": "bank",
    "amount": 5000
  }]
}, {
  "ctob": [{
    "id": "service",
    "name": "credit",
    "amount": 1000,
    "rate": 0.4
  }, {
    "id": "fund",
    "name": "credit",
    "amount": 3000,
    "rate": 0.2
  }, {
    "id": "others",
    "name": "credit",
    "amount": 4000,
    "rate": 0.6
  }]
}];

var flatList = objList.flatMap(obj => obj["btob"] || obj["ctob"]);
newObjList.forEach(newObj => flatList
  .filter(obj => obj.id == newObj.id && obj.name == newObj.name)
  .forEach(obj => Object.keys(newObj).forEach(key => obj[key] = newObj[key])));

console.log(objList);
buræquete
  • 14,226
  • 4
  • 44
  • 89
  • 1
    thanks for help, but want to return the obj without hardcoding keys ( `obj.amount`) – Senthil Jul 24 '19 at 04:30
  • @Senthil check again, I updated the logic so that key values are not hardcoded. But it will insert new fields from `newObj`, for example, can insert a `"rate": 0.4` to an obj in `objList` that had no such field, is that correct behaviour you want? – buræquete Jul 24 '19 at 04:36
0

The code below would generate the required object dynamically without any hardcoding on keys or values. If you want to return a totally new object then probably you can change return in the map function below to {... a} and {... childObj} as per ES6 to get a new copy of the inner objects.

function updateObj(list, newobj){
  const result = [];
  objList.forEach(obj => {
    Object.entries(obj).map(k => {
      const newRootObj = {};
      newRootObj[k[0]] = k[1].map(childObj => {
        const a = newObj.find(nObj => nObj.id === childObj.id && nObj.name === childObj.name);
        if(a) {
          childObj.amount = a.amount;
        }
        return childObj;
      });
      result.push(newRootObj);
    });
  });
  return result;
}

const newObj=[{
    "id": "service",
    "name": "bank",
    "amount": 2000
},{
    "id": "service",
    "name": "credit",
    "amount": 5000
}];


const objList=[
{
  "btob": [{
    "id": "service",
    "name": "bank",
    "amount": 1000
  },{
    "id": "fund",
    "name": "bank",
    "amount": 2000
  },{
    "id": "others",
    "name": "bank",
    "amount": 5000
   }]
},{
 "ctob":[{
    "id": "service",
    "name": "credit",
    "amount": 1000,
    "rate": 0.4
  },{
    "id": "fund",
    "name": "credit",
    "amount": 3000,
    "rate": 0.2
  },{
    "id": "others",
    "name": "credit",
    "amount": 4000,
    "rate": 0.6
   }]
  }];

const result = updateObj(objList, newObj);
console.log(result);
Sumit Surana
  • 1,554
  • 2
  • 14
  • 28
0

If you wanted a solution that relied on no hardcoding at all - that is, no "btob" or "ctob", you could use a .map() to loop through objList. For each item in it, loop through all of it's key/value pairs, and update matches using .find(). This also leaves your original object in-tact as opposed to overriding it.

Consider the sample below where I've added an additional key to demonstrate the extensibility.

var newObj = [
  { "id": "service", "name": "bank", "amount": 2000 },
  { "id": "service", "name": "credit", "amount": 5000 },
  { "id": "test", "name": "test", "newKey": "Hello world!"}
]; 
var objList = [
  { "btob": [{ "id": "service", "name": "bank", "amount": 1000 },{ "id": "fund", "name": "bank", "amount": 2000 },{ "id": "others", "name": "bank", "amount": 5000 }] },
  { "ctob":[{ "id": "service", "name": "credit", "amount": 1000, "rate": 0.4 },{ "id": "fund", "name": "credit", "amount": 3000, "rate": 0.2 },{ "id": "others", "name": "credit", "amount": 4000, "rate": 0.6 }]}, 
  { "dtob": [{ "id": "test", "name": "test"}]}
];

let result = objList
  .map(root => Object.keys(root)
    .reduce((output,key) => (
      {...output, [key]: root[key]
        .flatMap(i => {
          let replacement = newObj.find(f => i.id === f.id && i.name === f.name);
          return replacement ? {...i, ...replacement} : i;
        })
      }
    ), {})
  );

console.log(result);
Tyler Roper
  • 21,445
  • 6
  • 33
  • 56
-1

Iterate through both the arrays and modify if matches your condition.

Update: See how the nested(one level depth in your sample) objects are iterated.

objList.forEach(items => {
   items.forEach(item => {
      newObj.some(entry => {

          if (item.id === entry.id && item.name === entry.name) {
             item.amount = entry amount;
             return true;      //Break the inner loop (if no duplicate entries expected in objList) 
          }

      })
   })
})

Observe how the original array objects are referenced directly.

Charlie
  • 22,886
  • 11
  • 59
  • 90