user10022985
user10022985

Reputation:

Merge two arrays with deeply nested key with Ramda

I've recently started using Ramda to work with responses from JSONAPI. I am a bit confused as to how I should be merging two objects by a deeply nested key.

For example:

Take these two sets of data,

const users = [
    {   id: 1, 
        attributes: {
            firstName: "Bob",
            lastName: "Lee"
        }, 
        relationships: {
            phone: {
                data: {
                    id: 2, 
                    type: "phone"
                }
            }
        },
        type: "users"
     },
    {   id: 2, 
        attributes: {
            firstName: "Kevin",
            lastName: "Smith"
        }, 
        relationships: {
            phone: {
                data: {
                    id: 5, 
                    type: "phone"
                }
            }
        },
        type: "users"
     },
];

const phones= [
    {   id: 2, 
        attributes: {
            phoneNumber: "123-345-6789"
        },
        type: "phones"
     },
    {   id: 5, 
        attributes: {
            phoneNumber: "987-654-4321"
        }, 
        type: "phones"
     },
];

What I want to create is a new array with the related phone added to the user array with a new key holding all related objects, like this:

const newUser = 
[
  { id: 1,
    attributes: {
      firstName: "Bob",
      lastName: "Lee"
    },
    relationships: {
      phone: {
        data: {
          id: 2,
          type: "phones"
        }
      }
    },
    included: {
      phoneNumber: "123-345-6789"
    }
  },
  { id: 2,
    attributes: {
      firstName: "Kevin",
      lastName: "Smith"
    },
    relationships: {
      phone: {
        data: {
          id: 5,
          type: "phones"
        }
      }
    },
    type: "users",
    included: {
      phoneNumber: "987-654-4321"
    }
  }
]

I've tried multiple methods like map, pick, and join but the objects just don't seem to want to merge the way I want them to. The following code puts both of the objects into the same array, but I can't seem to wrap my head around where to go next.

const data = R.pipe(
        R.juxt([
          R.pipe(R.path(['users'])),
          R.pipe(R.path(['phones']))
        ]),
      )
}),

Upvotes: 0

Views: 1596

Answers (1)

Scott Sauyet
Scott Sauyet

Reputation: 50797

Here's my first approach:

const {map, path, find, propEq, assoc} = R

const addPhones = (phones, users) => map(user => {
  const phoneId = path(['relationships', 'phone', 'data', 'id'], user)
  const phone = find(propEq('id', phoneId), phones)
  return phone
    ? assoc('included', phone.attributes, user)
    : user
}, users)


const users = [{"attributes": {"firstName": "Bob", "lastName": "Lee"}, "id": 1, "relationships": {"phone": {"data": {"id": 2, "type": "phone"}}}, "type": "users"}, {"attributes": {"firstName": "Kevin", "lastName": "Smith"}, "id": 2, "relationships": {"phone": {"data": {"id": 5, "type": "phone"}}}, "type": "users"}, {"attributes": {"firstName": "Nancy", "lastName": "Johnson"}, "id": 3, "relationships": {"phone": {"data": {"id": 6, "type": "phone"}}}, "type": "users"}]

const phones= [{"attributes": {"phoneNumber": "123-345-6789"}, "id": 2, "type": "phones"}, {"attributes": {"phoneNumber": "987-654-4321"}, "id": 5, "type": "phones"}, {"attributes": {"phoneNumber": "212-867-5309"}, "id": 7, "type": "phones"}]


console.log(addPhones(phones, users))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>

This version deals appropriately with missing values in either list. If there is a user with no matching phone, the user is returned as-is, with no included property. And if there is a phone with no matching user, it is simply ignored.

This makes the assumption that you can include the entire phone.attributes object in your user. If you need to include only the phoneNumber, it's only slightly more complex, replacing the obvious line with

    ? assocPath(['included', 'phoneNumber'], phone.attributes.phoneNumber, user)

Upvotes: 1

Related Questions