两个分页接口合并查询
钢翼
编程
在面向接口编程时,有时业务需要将两个分页接口的数据合并输出成一个分页结果,当无法通过数据库的方式进行合并的时候,可以考虑通过查询全部数据,在内存中合并的方式来实现,但是当分页数据很多的时候排序和内存占用问题就会很突出。为了避免这个问题的发生,我们可以通过从头开始查询,当达到分页记录的时候结束查询,并每个接口各取2页记录,进行合并,最后输出(查询接口的次数为分页数+2)。文字描述有点麻烦,看代码吧。以下代码用js来实现,主要是方便理解和测试。
<html>
<body>
<script>
function sortNumber(a, b) {//排序用
return a - b
}
//模拟数据
var m1_arr = [];
var m2_arr = [];
var timer = 0;
//造数
function initData() {
for (var i = 0; i < 1000; i++) {
if (Math.random() < 0.7) {//设置两个数组的比例
m1_arr.push(i);
} else {
m2_arr.push(i);
}
}
}
initData();
//造数 end
function m1(page, size) {//m1分页接口
timer++;
var list = [];
for (var i = (page - 1) * size; i < page * size && i < m1_arr.length; i++) {
list.push(m1_arr[i]);
}
console.log('m1:' + page);
return { list: list, page: page, total: m1_arr.length, size: size };
}
function m2(page, size) {//m2分页接口
timer++;
var list = [];
for (var i = (page - 1) * size; i < page * size && i < m2_arr.length; i++) {
list.push(m2_arr[i]);
}
console.log('m2:' + page);
return { list: list, page: page, total: m2_arr.length, size: size };
}
function getData(m1_idx, m2_idx, size, oldObj) {//合并查询,避免重复查询
if (oldObj.m1_idx != m1_idx) {
oldObj.m1_data = m1(m1_idx, size);
oldObj.m1_idx = m1_idx;
}
if (oldObj.m2_idx != m2_idx) {
oldObj.m2_data = m2(m2_idx, size)
oldObj.m2_idx = m2_idx;
}
return oldObj;
}
function m(page, size) {//汇总新接口
timer = 0;
var m1_idx = 1;
var m2_idx = 1;
var obj = {};
var m1_count = 0 ;
var m2_count = 0;
while (true) {
obj = getData(m1_idx, m2_idx, size, obj)
var m1_obj = obj.m1_data;
var m2_obj = obj.m2_data;
if ((page - 1) * size > m1_obj.total + m2_obj.total) {//超过总条数
return { list: [], page: page, total: obj.m1_list.total + obj.m2_list.total, size: size };
}
m1_count = (m1_idx - 1) * size;
m2_count = (m2_idx - 1) * size;
if (m1_count > m1_obj.total) {
m1_count = m1_obj.total;
}
if (m2_count > m2_obj.total) {
m2_count = m2_obj.total;
}
if (m1_count + m2_count + 2 * size >= page * size) {//已达到数量退出循环
break;
}
if (m1_obj.list.length == 0) {//m1没数据了
m2_idx++;
} else if (m2_obj.list.length == 0) {//m2没数据了
m1_idx++;
} else {
var m1_min = m1_obj.list[0];
var m2_min = m2_obj.list[0];
var m1_max = m1_obj.list[m1_obj.list.length - 1];
var m2_max = m2_obj.list[m2_obj.list.length - 1];
if (m1_min > m2_max) {//m1都比m2大
m2_idx++;
} else if (m2_min > m1_max) {//m2都比m1大
m1_idx++;
} else if (m1_min < m2_min && m1_max > m2_max) {//m2被包含
m2_idx++;
} else if (m1_min > m2_min && m1_max < m2_max) {//m1被包含
m1_idx++;
} else if (m1_min < m2_min && m1_max < m2_max) {//m1在左边
m1_idx++;
} else if (m1_min > m2_min && m1_max > m2_max) {//m2在左侧
m2_idx++;
}
}
}
//为什么要各自查两页,因为数据组成有以下几种情况,查两页可以包括所有情况
//m1分页1
//m1分页1 + m1分页2
//m2分页1
//m2分页1 + m2分页2
//m1分页1 + m2分页1 不考虑m1和m2的顺序
//m1分页1 + m1分页2 + m2分页1 不考虑m2的顺序
//m2分页1 + m2分页2 + m1分页1 不考虑m1的顺序
var list = [];
list = list.concat(obj.m1_data.list);
list = list.concat(obj.m2_data.list);
obj = getData(m1_idx + 1, m2_idx + 1, size, obj)
list = list.concat(obj.m1_data.list);
list = list.concat(obj.m2_data.list);
list = list.sort(sortNumber);
var count = m1_count + m2_count;
var start = (page - 1) * size - count;
var result = [];
for (var i = start; i < start + size && i < list.length; i++) {
result.push(list[i]);
}
console.log('m1,m2查询次数:' + timer)
return { list: result, page: page, total: obj.m1_data.total + obj.m2_data.total, size: size };
}
console.log(m(6, 2));
</script>
</body>
</html>