一次数据映射的思考

601 阅读4分钟

在前后端分离的开发中,经常会遇到这样的情形。

需求评估通过,设计图出来了。前端根据设计图和需求,完成了静态页面的展示和mock数据。过了一段时间后,后端把这个需求的接口写好了。前端调用时,发现返回的数据结构和自己mock的数据不一致。

这可能是前后端思考的角度不同导致的。

比如,前端展示时所需要的数据结构如下:

{
	name:'xx',
	age:15,
	like:'pkay',
	bastFriends:[
		{
			name:
		}
	]
}

而后端返回来的,是这样的

{
	name:'xx',
	age:15,
	like:'play',
	list:[
	{
		name:...
	}
	]
}

不算太糟,对吧,只是key不一致的情况,我们可以直接

item.bastFriends = item.list

但如果是十分复杂的嵌套情形。

{
	...
	arr1:[
		{
			inner_arr:[
				{...}
			]
		},{...}
	]
}

就需要一些思考了。

这是前端展示的数据结构:

{
	id:1
	name:"志愿表1",
	rank:10000,
	range:3000,
	subject:化学,技术,历史,
	school_info:[
		{//第一个大学
			sname:'中央民族大学',
			rank:7772,
			mark_line:653,
			section:1,
			professional:[
			//该大学下填报的志愿
			{	//第一个志愿
				id:706,
				subject_require:历史,
				major_code:017,
				major_cat:民族学,
				plan_num:2,
				line:653,
				rank:7772,
				year:2020,
				section:1,	
			},{
				//第二个志愿
				id:649,
				subject_require: "无",
				major_code: "016",
				major_cat: "汉语言文学",
				plan_num: 2,
				line:654,
				rank: 7391,
				year: 2020,
				section: 1,
			}
			]
		},{//第二个大学
			....
		}
	]
}

这是后端返回的数据结构:

{
	id: 1,
	name: "志愿表1",
	query_param: {"rank":"10000","range":"3000","subject":"\u5316\u5b66,\u6280\u672f,\u5386\u53f2"},
	list: [
	{
		//第一个志愿,没有以大学为单位区分
		id:43,
		list_id:12,
		markline_id:706
		markline:[
			{
				id:706,
				line:653,
				major_cat: "民族学",
				major_code: "017",
				plan_num: 2,
				rank: 7772,
				school_id: 10,
				school_name: "中央民族大学",
				section: 1,
				subject_require: "历史",
				year: 2020,
			}
		]
	},{
		//第二个志愿
		id:44,
		list_id:13,
		markline_id:649
		markline:[
			{
				id:649,
				line:654,
				major_cat: "汉语言文学",
				major_code: "016",
				plan_num: 2,
				rank: 7391,
				school_id: 10,
				school_name: "中央民族大学",
				section: 1,
				subject_require: "无",
				year: 2020,
			}
		]
	},{
		//第三个志愿,是其他学校的
	}
		
	]
}

莫慌,一切都有迹可循。

思考这样一个问题:需要展示的数据从哪里获取?

1.需要把rank,range,subject从query_param里解析出来。这个不难 ,考虑到测试数据可能不规范,设置了默认值。

let {rank,range,subject} = JSON.parse(data.query_param)||{rank:100,range:1000,subject:'无'}

2.需要将list中的数据按学校分组,庆幸的是有学校id可以作为分组依据。期望分组后得到的数据结构如下:

let obj = {'10':[
			{
				//第一个志愿,现在以大学id为单位区分
				id:43,
				list_id:12,
				markline_id:706
				markline:[
				{
					id:706,
					line:653,
					major_cat: "民族学",
					major_code: "017",
					plan_num: 2,
					rank: 7772,
					school_id: 10,
					school_name: "中央民族大学",
					section: 1,
					subject_require: "历史",
					year: 2020,
				}
				]
			},{
				//第二个志愿
				id:44,
				list_id:13,
				markline_id:649
				markline:[
				{
					id:649,
					line:654,
					major_cat: "汉语言文学",
					major_code: "016",
					plan_num: 2,
					rank: 7391,
					school_id: 10,
					school_name: "中央民族大学",
					section: 1,
					subject_require: "无",
					year: 2020,
				}
				]
			}
		],
		'11':[{
			//第三个志愿
		}]
}

[].reduce可以做到这一点。参考MDN的例子。

let appligroupBySchool = arr.reduce((acc,obj)=>{
    let key = obj.markline.school_id
    if(!acc[key]){
        acc[key] = []
     }
    acc[key].push(obj)
    return acc
},{})

再观察一下前端的数据结构。

shchool_info下第一层的数据:sname,rank,mark_line,section。都可以从第二层的数据markline中获取。

  • 其中,rank和mark_line需要遍历一边markline找出最小值,而sname和section可以直接从markline[0]中获取。
  • 而professional需要遍历一次分组,获取每组下markline的值,并保存成数组。

for(prop in obj)可以遍历对象。obj['10']就是分组后的其中一组。 [].sort(func)可以找出最小值。 于是,我们可以在遍历对象的循环内,做这样的操作:

let school_info_item = {}
let arr = obj[prop]
let markLine = []
arr.forEach(item=>{
//获取每组下markline的值,并保存成数组
    item.markline.m_id = item.id
    markLine.push(item.markline)
})
//升序排序下数组
markLine = markLine.sort(compare('line','up'))
//获取需要的数据
infoItem.sname = markLine[0].school_name
infoItem.rank = markLine[0].rank
infoItem.mark_line = markLine[0].line
infoItem.section = markLine[0].section
infoItem.professional = markLine

至此为止,从接口获取的数据就转换成了前端展示所需的数据。增加了一些属性保证显示正确,这样肯定会造成属性冗余。 我的想法是,如果数据只需要用来展示,不做任何增删改的操作,可以把冗余的属性用 delete 属性名 给删掉。

还有一些地方需要注意:增删改操作,需要调用接口时,要根据接口参数,做数据转换。 这个需要具体问题具体分析,在这个案例中,增删改调用的接口还蛮简单的,只用传对应id和修改值就行了。 调用成功后,需要重新获取一次数据,重新初始化一次。