Merge two arrays with deeply nested key with Ramda

Multi tool use
Multi tool use


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']))
]),
)
}),





Are your actual object arrays? Your samples use {} for the outer brackets, but no keys. Should they be ?
– Scott Sauyet
Jul 2 at 19:42


{}






Also in type: phone, is phone defined elsewhere, or should this just be a string?
– Scott Sauyet
Jul 2 at 19:49


type: phone





Actually it is in fact an object.. but I can turn it into an array with R.values, right? Also phone should be a string, sorry! I will edit that
– davidhong
Jul 2 at 19:56






Well, your sample code doesn't have any keys...
– Scott Sauyet
Jul 2 at 20:19





I changed the sets of data to arrays
– davidhong
Jul 2 at 20:35




1 Answer
1



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))


//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js



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.


included



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


phone.attributes


phoneNumber


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





thanks, i will look into this approach. is it possible to do all of this in one pipe?
– davidhong
Jul 3 at 17:42






I'm not sure what you mean by "all in one pipe". If you mean a point-free version of it, then I'd say it would not be pretty.
– Scott Sauyet
Jul 6 at 0:27






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

1D9QDWusLjpTkcAGVrr MBxyU0w,1S82H VW9AObFrHKuA4HA1Os7TdAkJwWkH8kmGufmzQMLPq3DDHT3gVmul
a5FO1clGHi,QOp

Popular posts from this blog

PHP contact form sending but not receiving emails

Do graphics cards have individual ID by which single devices can be distinguished?

Create weekly swift ios local notifications