Search code examples
javascriptarraysfull-outer-join

Full outer join of two js arrays containing objects - joined array contains new property 'action' (add/remove/edit/same)


I have two arrays originalArray and modifiedArray which have objects with some properties; sys_id is the unique property:

originalArray = [
    { sys_id: 1234, type: 'XYZZ' }, 
    { sys_id: 1235, type: 'ABCD' }, 
    { sys_id: 1236, type: 'IJKL' },
    { sys_id: 1237, type: 'WXYZ' }, 
    { sys_id: 1238, type: 'LMNO' }
]

modifiedArray = [
    { sys_id: 1234, type: 'XYZZ' }, 
    { sys_id: 1235, type: 'ZZAA' },  
    { sys_id: 1236, type: 'ZZZZ' },
    { sys_id: 1252, type: 'AAAA' }
]

I'm looking to combine/merge the arrays but include a new property that describes a full account of what changed in the new array based on the original array using the sys_id property.

resultingArray = [
    { sys_id: 1234, type: 'XYZZ', action: 'same' }, 
    { sys_id: 1235, type: 'ZZAA', action: 'edit' }, 
    { sys_id: 1236, type: 'ZZZZ', action: 'edit' },
    { sys_id: 1237, type: 'WXYZ', action: 'remove' }, 
    { sys_id: 1238, type: 'LMNO', action: 'remove' },
    { sys_id: 1252, type: 'AAAA', action: 'add' }

Also would like to know if there is more proper terminology, or a more concise way to explain what I'm trying to accomplish here?

I'm on a platform that is limited to ES5.


Solution

  • Using Array#reduce() to make object that uses sys_id as keys and has properties orig and mod then a good old for in loop to iterate that object and compare the 2 types when they exist or check which doesn't exist and push proper data to results array.

    All ES5 compatible

    var grouped = [originalArray, modifiedArray].reduce(function(acc, arr, i) {
      var label = i === 0 ? 'orig' : 'mod';
      for (var j = 0; j < arr.length; j++) {
        var curr = arr[j], id = curr.sys_id;
        acc[id] = acc[id] || {orig: null, mod: null };
        acc[id][label] = curr;
      }
      return acc;
    }, {});
    
    var res = [];
    
    function insertObj(o, act) {
      var newObj = { action: act };
      // iterate existing keys to add to new object
      for (var k in o) {
        if (o.hasOwnProperty(k)) {
          newObj[k] = o[k]
        }
      }
      res.push(newObj)
    }
    
    for (var key in grouped) {
      var action, obj;
      if (grouped.hasOwnProperty(key)) { 
        obj = grouped[key]
        if (!obj.orig) {
          insertObj(obj.mod, 'add');
        } else if (!obj.mod) {
          insertObj(obj.orig, 'remove')
        } else {
          action = obj.mod.type === obj.orig.type ? 'same' : 'edit';
          insertObj(obj.mod, action)
        }
      }
    }
    
    console.log(res)
    <script>
    
    var originalArray = [
        { sys_id: 1234, type: 'XYZZ' }, 
        { sys_id: 1235, type: 'ABCD' }, 
        { sys_id: 1236, type: 'IJKL' },
        { sys_id: 1237, type: 'WXYZ' }, 
        { sys_id: 1238, type: 'LMNO' }
    ]
    
    var modifiedArray = [
        { sys_id: 1234, type: 'XYZZ' }, 
        { sys_id: 1235, type: 'ZZAA' },  
        { sys_id: 1236, type: 'ZZZZ' },
        { sys_id: 1252, type: 'AAAA' }
    ]
    </script>