javascriptarraysobjectramda.js

Merge three arrays with ramda


I've recently started using Ramda to work with responses from JSONAPI and I am having some trouble dealing with complex relationships.. I have a big array with three smaller arrays, and I need to merge the three smaller arrays, but each array has a different property. I need one array with those three different properties.

For example:

const bigArray = [[...], [...], [...]] 

arrayOne = [
  { 
    id = 1,
    attributes = {...},
    specialProperty1 = {...}
  },
  { 
    id = 2,
    attributes = {...},
    specialProperty1 = {...}
  }
]

arrayTwo = [
  { 
    id = 1,
    attributes = {...},
    specialProperty2 = {...}
  },
  { 
    id = 2,
    attributes = {...},
    specialProperty2 = {...}
  }
]

arrayThree = [
  { 
    id = 1,
    attributes = {...},
    specialProperty3 = {...}
  },
  { 
    id = 2,
    attributes = {...},
    specialProperty3 = {...}
  }
]

Identical id's represent the SAME person. i.e. id 1 in arrayOne is referencing the same person as id 1 in arrayTwo. Therefore the attributes are the same as well. The only difference between these three arrays are the special properties. I need the entire object of each special property to be merged so that all three special properties are in the object with the corresponding id.

Like this:

const newArray = [
  { 
    id = 1,
    attributes = {...},
    specialProperty1 = {...},
    specialProperty2 = {...},
    specialProperty3 = {...}
  },
  { 
    id = 2,
    attributes = {...},
    specialProperty1 = {...},
    specialProperty2 = {...},
    specialProperty3 = {...}
  },
]

ALSO, this is being returned in a promise.All, so it is important to note that the three smaller arrays are all in one big array. I think this is what's tripping me up the most and I'm having trouble figuring out which Ramda methods to use to reference the three arrays within the big array.


Solution

  • One way to approach this would be to index by the id property of each array, then merge each corresponding array elements by their matching id and their contents. Then finally extract the values of the outer indexed objects.

    const
    arrayOne = [
      { 
        id: 1,
        attributes: {},
        specialProperty1: {}
      },
      { 
        id: 2,
        attributes: {},
        specialProperty1: {}
      }
    ],
    
    arrayTwo = [
      { 
        id: 1,
        attributes: {},
        specialProperty2: {}
      },
      { 
        id: 2,
        attributes: {},
        specialProperty2: {}
      }
    ],
    
    arrayThree = [
      { 
        id: 1,
        attributes: {},
        specialProperty3: {}
      },
      { 
        id: 2,
        attributes: {},
        specialProperty3: {}
      }
    ],
    
    fn = R.pipe(
      R.map(R.indexBy(R.prop('id'))),
      R.reduce(R.mergeWith(R.merge), {}),
      R.values
    ),
    
    newArray = fn([arrayOne, arrayTwo, arrayThree])
    
    console.log(newArray)
    <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>