Here is my data structure (abbreviated, and you can skip over this until you get to the heart of my question below):
var data = {
jsonapi: { version: '1.0' },
data: {
type: 'mobile_screens',
id: '1',
attributes: { title: 'Watch' },
relationships: {
mobile_screen_components: {
data: [
{ type: 'mobile_screen_components', id: '1_1' },
{ type: 'mobile_screen_components', id: '1_2' },
],
},
},
},
included: [
{
type: 'videos',
id: '5590720024001',
attributes: {
thumbnail: {
width: 1280,
url:
'http://media2.XXXXX.com/BrightCove/694940094001/2017/09/27/694940094001_5590729403001_5590720024001-vs.jpg?pubId=694940094001',
height: 720,
},
start_air_date: '2017-09-27T16:32:00.000Z',
streams: [
{
url:
'http://XXXXX-f.akamaihd.net/i/BrightCove/694940094001/2017/09/27/694940094001_55907,27023001_5590720024001,30873001_5590720024001,32416001_5590720024001,32423001_5590720024001,32792001_5590720024001,32896001_5590720024001,.mp4.csmil/master.m3u8',
mime_type: 'MP4',
},
],
last_modified_date: '2017-09-27T16:50:13.471Z',
description: 'House Republicans renew call amid fresh Comey concerns',
},
},
{
type: 'videos',
id: '5590670324001',
attributes: {
...
},
},
{
type: 'videos',
id: '5590665282001',
attributes: {
...
},
},
{
id: '20fb845a-72ad-4d5f-a27a-c01efd857f76',
type: 'articles',
attributes: {
fn__legacy_type: 'articles',
title: 'Restaurant plans ginormous site near Wall Street, Ground Zero',
fn__media_tags: ['business'],
last_published_date: '2017-09-20T18:20:29.526Z',
thumbnail: {
image: {
url:
'https://secure.media.foxnews.com/BrightCove/990505083001/990505083001/2017/09/13/990505083001_5575086468001_5574853539001-vs.jpg?pubId=694940094001',
},
},
},
relationships: {
components_relationships: {
data: [
{
id: 'article_id_7',
type: 'videos',
},
{
id: 'article_id_8',
type: 'videos',
},
],
},
},
},
{
id: 'e6e327ec-ebb2-4220-a391-41f798e654f7',
type: 'articles',
attributes: {
...
},
relationships: {
...
},
},
{
type: 'mobile_screen_components',
id: '1_1',
attributes: { display_type: 'shelf', title: 'Featured Playlist' },
relationships: {
videos: {
data: [
[
{ type: 'videos', id: '5590720024001' },
{ type: 'videos', id: '5590670324001' },
{ type: 'videos', id: '5590665282001' },
{
id: '20fb845a-72ad-4d5f-a27a-c01efd857f76',
type: 'articles',
},
{
id: 'e6e327ec-ebb2-4220-a391-41f798e654f7',
type: 'articles',
},
],
},
articles: {
data: [
{
id: '20fb845a-72ad-4d5f-a27a-c01efd857f76',
type: 'articles',
},
{
id: 'e6e327ec-ebb2-4220-a391-41f798e654f7',
type: 'articles',
},
],
}
},
},
{
type: 'videos',
id: '1241186546001',
attributes: {
...
},
},
{
type: 'videos',
id: '1251429410001',
attributes: {
...
},
},
{
type: 'mobile_screen_components',
id: '1_2',
attributes: { display_type: 'shelf', title: 'Live TV' },
relationships: {
videos: {
data: [
{ type: 'videos', id: '1241186546001' },
{ type: 'videos', id: '1251429410001' },
],
},
},
},
{
type: 'videos',
id: '2013931500001',
attributes: {
...
},
},
{
type: 'mobile_screen_components',
id: '1_3',
attributes: { display_type: 'shelf', title: 'Live Streams' },
relationships: {
videos: {
data: [{ type: 'videos', id: '2013931500001' }],
},
},
},
],
};
For each object in the included
array, I would like to check of it has a type
of "mobile_screen_components." If it does, I would like to grab all the objects inside that parent object's relationship
property (e.g.
videos
, articles
, shows
, etc.) and grab each respective data
array. Finally, all these arrays would be concatenated, and place under a new data
array, which will be a property of an items
array, which is now the sole property of the original object.
That is to say that
{
type: 'mobile_screen_components',
id: '1_1',
attributes: { display_type: 'shelf', title: 'Featured Playlist' },
relationships: {
videos: {
data: [
[
{ type: 'videos', id: '5590720024001' },
{ type: 'videos', id: '5590670324001' },
{ type: 'videos', id: '5590665282001' }
]
},
articles: {
data: [
{
id: '20fb845a-72ad-4d5f-a27a-c01efd857f76',
type: 'articles',
},
{
id: 'e6e327ec-ebb2-4220-a391-41f798e654f7',
type: 'articles',
},
],
}
},
}
would become
{
type: 'mobile_screen_components',
id: '1_1',
attributes: { display_type: 'shelf', title: 'Featured Playlist' },
relationships: {
items: {
data: [
[
{ type: 'videos', id: '5590720024001' },
{ type: 'videos', id: '5590670324001' },
{ type: 'videos', id: '5590665282001' },
{
id: '20fb845a-72ad-4d5f-a27a-c01efd857f76',
type: 'articles',
},
{
id: 'e6e327ec-ebb2-4220-a391-41f798e654f7',
type: 'articles',
},
],
],
},
},
}
I want to use a lens as to return to whole of the structure with just this transformation applied. My initial stab at this does not work:
const getMCRel = (type, rels) => {
if (type === 'mobile_screen_components' ) {
return rels
}
return undefined
}
const findMCRel = R.compose(getMCRel, R.props(['type','relationships']));
const rLens = R.lens(findMCRel, R.assoc('relationships'));
const itemsWrapper = (arr) => ({"items": arr});
const result = R.map(R.over(rLens,R.compose(itemsWrapper, R.values)),data.included)
This doesn't get you all of the way, but for the conversion of the "mobile_screen_components" part, you could use something like this:
const simplify = over(
lensProp('relationships'),
pipe(pluck('data'), values, flatten, objOf('data'), objOf('items'))
)
simplify(stuff)
You can see this in action in the Ramda REPL.
And to test if your item is of the correct type, you simply use:
propEq('type', 'mobile_screen_component')
But your requirements are not clear enough to me to know if you want to reject
those that are not of the right type or whether you want to map
and apply that function only when
this predicate is true.
Trying to work your full requirements, as much as I understand them, you might try something like:
const simplifyAll = over(
lensProp('included'),
map(when(propEq('type', 'mobile_screen_components'), simplify))
)
simplifyAll(data)
This leaves a lot of undefined
s in many of the relationships/items/data
lists. If you want to get rid of them, you might update simplify
to add reject(isNil)
after flatten
:
const simplify = over(
lensProp('relationships'),
pipe(pluck('data'), values, flatten, reject(isNil), objOf('data'), objOf('items'))
)
You can see this version too in the Ramda REPL.
Finally, if this is the only use of the simplify
function, you could move it inline. I would recommend against it, as the resulting wall of text is unlikely to be as readable as the above version. But it's your call.