用 ramda.js 重新排列 JSON - 基于兄弟元素的镜头?

rearranging JSON with ramda.js - lens based on sibling element?

这是我的数据结构(缩写,你可以跳过这个直到你进入我下面问题的核心):

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

对于 included 数组中的每个对象,我想检查它是否具有 "mobile_screen_components." 的 type 如果是,我想获取其中的所有对象该父对象的 relationship 属性(例如 videosarticlesshows 等)并获取每个相应的 data 数组。最后,所有这些数组将被连接起来,并放置在一个新的 data 数组下,这将是 items 数组的 属性,现在是唯一的 属性原始对象。

也就是说

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

会变成

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

我想对整个结构使用 return 镜头,只应用此转换。我最初对此的尝试不起作用:

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)

这并不能完全解决问题,但是对于 "mobile_screen_components" 部分的转换,您可以使用如下内容:

const simplify = over(
  lensProp('relationships'), 
  pipe(pluck('data'), values, flatten, objOf('data'), objOf('items'))
)

simplify(stuff)

您可以在 Ramda REPL.

中看到实际效果

要测试您的商品类型是否正确,您只需使用:

propEq('type', 'mobile_screen_component')

但是你的要求对我来说还不够清楚,我无法知道你是否想 reject those that are not of the right type or whether you want to map and apply that function only when 这个谓词是真的。

更新

尝试满足您的全部要求,据我所知,您可以尝试类似的方法:

const simplifyAll = over(
  lensProp('included'), 
  map(when(propEq('type', 'mobile_screen_components'), simplify))
)

simplifyAll(data)

这会在许多 relationships/items/data 列表中留下很多 undefined。如果你想摆脱它们,你可以更新 simplify 以在 flatten:

之后添加 reject(isNil)
const simplify = over(
  lensProp('relationships'), 
  pipe(pluck('data'), values, flatten, reject(isNil), objOf('data'), objOf('items'))
)

你也可以在 Ramda REPL.

中看到这个版本

最后,如果这是 simplify 函数的唯一用途,您可以将其内联。我会反对它,因为由此产生的文本墙不太可能像上面的版本那样可读。但这是你的决定。