用 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
属性(例如
videos
、articles
、shows
等)并获取每个相应的 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
函数的唯一用途,您可以将其内联。我会反对它,因为由此产生的文本墙不太可能像上面的版本那样可读。但这是你的决定。
这是我的数据结构(缩写,你可以跳过这个直到你进入我下面问题的核心):
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
属性(例如
videos
、articles
、shows
等)并获取每个相应的 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
函数的唯一用途,您可以将其内联。我会反对它,因为由此产生的文本墙不太可能像上面的版本那样可读。但这是你的决定。