Functional programming / Ramda: Creating a new object by picking nested properties

1.8k Views Asked by At

Functional programming newbie here. I have this object:

{ 
  _id: '2014d5db-55dc-4078-ae87-382c226d0785',
  _source: { 
    phone: '00447827434313',
    ...
  } 
}

In the end I want to have it in this format:

{ 
  id: '2014d5db-55dc-4078-ae87-382c226d0785',
  phone: '00447827434313',
  ...
}

Basically extracting _source, and renaming _id to id.

I created this function below which works, but I'm trying use only Ramda's functions instead of creating new objects by hand. I assume it's more "functional" way, let me know if it doesn't really matter.

const test = o => merge(o._source, { id: o._id })

Thanks very much

1

There are 1 best solutions below

2
On BEST ANSWER

I don't think there's a particular built-in Ramda function for that. But it's not hard to write one on top of lensPath, view, and map:

const remap = R.curry((desc, obj) => R.map(path => R.view(R.lensPath(path), obj), desc));

const myExtract = remap({
  id: ['_id'],
  phone: ['_source', 'phone']
});

myExtract(input);
//=> {"id": "2014d5db-55dc-4078-ae87-382c226d0785", "phone": "00447827434313"}

It only works this simply if your output is described as a flat list of fields (of course their properties could themselves be objects.) But one where you pulled from nested paths and pushed to nested paths would not be too much harder to write. The user API would be uglier, though, I imagine.

I don't see any clean way to make this points-free and still retain readability. Perhaps someone else might manage that, but I think this is already pretty nice.

You can see this in action on the Ramda REPL.