两个分页接口合并查询

返回
Author Avatar
钢翼
2019-08-28
编程
300

在面向接口编程时,有时业务需要将两个分页接口的数据合并输出成一个分页结果,当无法通过数据库的方式进行合并的时候,可以考虑通过查询全部数据,在内存中合并的方式来实现,但是当分页数据很多的时候排序和内存占用问题就会很突出。为了避免这个问题的发生,我们可以通过从头开始查询,当达到分页记录的时候结束查询,并每个接口各取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>