改善猫鼬 find() 查询执行时间

时间:2021-03-16 14:37:12

标签: node.js mongoose

这是 MEAN 项目的一部分。 在 UI 上,正在显示服务日志表(mat-table)。该表还具有 matSort 和 matPagination。 UI 有多个过滤器选项(mat-select)加上一个搜索输入字段来过滤从服务器接收的数据。为了从服务器获取数据,使用了下面的 Node 服务方法。它基本上是猫鼬 find() 查询的变体。请注意,以下代码中的“filtObj”是以角度创建的对象数组,用于定义用户选择的过滤器。代码中给出了示例。

对于测试设置,我在 ServiceLog 集合中只有 20 个文档。 只有 20 个文档,执行节点服务方法所需的时间约为 1.5 秒。在生产环境中,到年底,集合中的文档数量可能会达到 7,000 到 10,000。我担心在完全加载集合的情况下执行数据获取所需的时间。

请告知以下方法中的代码是否可以改进。

async function getServiceLog(filter, sortKey, sortOrder, pageSize, pageIndex, filtObj){
  console.time('getServiceLog');
  let fetchedDocs;
  let docQuery;


  ////////////// example of a filtObj:  [ { FY: '2020-21' }, { dueMonth: '2020-07' } ]
  ///////////// There are 9 filters in UI, some or all may be applied by the user.
  /////////////  If no filter is applied then filtObj = []

  let filtType = 'none';   /// to indicate that user did not search for any text nor applied any filter

  if(filter && filtObj.length <= 0) {         /// user typed something in search input but no filters
    filtType = 'filter'                       
  } else if(!filter && filtObj.length > 0) {  /// no Search input but One or more filters were applied
    filtType = 'filtObj'                      
  } else if(filter && filtObj.length > 0) {   /// both of the above
    filtType = 'both'                         
  }

  switch(filtType) {
    case "none":
      docQuery = ServiceLog.find().collation({ locale: 'en'});
      break;

    case "filter":        /// searching only in compName and servNAme fields
      docQuery = ServiceLog.find({
        $or: [
          { compName: { $regex:  filter, $options: 'i' } },
          { servName: { $regex:  filter, $options: 'i' } },
        ],
        }).collation({ locale: 'en'});
      break;

    case "filtObj":
      docQuery = ServiceLog.find({
            $and: filtObj
        }).collation({ locale: 'en'});
      break;

    case "both":
      docQuery = ServiceLog.find({
        $and: [
          {
            $or: [
              { compName: { $regex:  filter, $options: 'i' } },
              { servName: { $regex:  filter, $options: 'i' } },
            ],
          },
          {
            $and: filtObj
          }
        ]
        }).collation({ locale: 'en'});
      break;
  }

  ///// the below block is to find out the correct count of documents matching the search/filter criteria
 
  fetchedDocs = await docQuery;
  if(!fetchedDocs) fetchedDocs = [];
  totalCount = fetchedDocs.length;
  if(!totalCount) totalCount = 0;


  /////// and after getting the filtered collection count I am modifying the query below
  /////// to sort and apply pageIndex/pageSize of matPaginator
  /////// so there are two query calls to the DB. Can the two calls be avoided?

  if(pageSize && pageIndex >= 0) {
    if(!sortKey) {
      docQuery.skip(pageSize * pageIndex).limit(pageSize);
    }else{
      if(sortOrder === 'desc') {
        sortOption = '-' + sortKey
      }else {
        sortOption = sortKey
      }
      docQuery.sort(sortOption).skip(pageSize * pageIndex).limit(pageSize);
    }
  }

  fetchedDocs = await docQuery;
  if(!fetchedDocs) fetchedDocs = [];

  servLogFilts = await getServiceLogFilters();  // given below

  servLogData = {
    servicelogs: fetchedDocs,
    totalCount: totalCount,
    servLogFilts: servLogFilts
  }

  console.timeEnd('getServiceLog');

  return servLogData;
}
///////////// END OF getServiceLog function


//// the below function generates the array of options for each filter in the UI
//// this is causing multiple calls to the collection. How to improve this?
async function getServiceLogFilters() {

  arrFY = await ServiceLog.distinct('FY');
  if(!arrFY) {
    arrFY = [];
  } else {
    arrFY.sort();
    arrFY.reverse();
  }

  arrCalYear = await ServiceLog.distinct('calYear');
  if(!arrCalYear) {
    arrCalYear = [];
  } else {
    arrCalYear.sort();
    arrCalYear.reverse();
  }

  arrCalMonth = await ServiceLog.distinct('calMonth');
  if(!arrCalMonth) {
    arrCalMonth = [];
  } else {
    arrCalMonth.sort();
    arrCalMonth.reverse();
  }

  arrDueMonth = await ServiceLog.distinct('dueMonth');
  if(!arrDueMonth) {
    arrDueMonth = [];
  } else {
    arrDueMonth.sort();
    arrDueMonth.reverse();
  }

  arrCompCat = await ServiceLog.distinct('compCat');
  if(!arrCompCat) {
    arrCompCat = [];
  } else {
    if(arrCompCat.length = 1 && arrCompCat[0] === '') {
      arrCompCat = [];
    } else {
      arrCompCat.sort();
    }
  }

  arrServStatus = await ServiceLog.distinct('servStatus');
  if(!arrServStatus) {
    arrServStatus = [];
  } else {
    arrServStatus.sort();
  }

  arrServCat = await ServiceLog.distinct('servCat');
  if(!arrServCat) {
    arrServCat = [];
  } else {
    arrServCat.sort();
  }

  arrExecName = await ServiceLog.distinct('execName');
  if(!arrExecName) {
    arrExecName = [];
  } else {
    arrExecName.sort();
  }

  arrPaytStatus = await ServiceLog.distinct('paytStatus');
  if(!arrPaytStatus) {
    arrPaytStatus = [];
  } else {
    arrPaytStatus.sort();
  }

  const servLogFilts = {
    arrFY: arrFY,
    arrCalYear: arrCalYear,
    arrCalMonth: arrCalMonth,
    arrDueMonth: arrDueMonth,
    arrCompCat: arrCompCat,
    arrServStatus: arrServStatus,
    arrServCat: arrServCat,
    arrExecName: arrExecName,
    arrPaytStatus: arrPaytStatus
  }

  return servLogFilts;
}


0 个答案:

没有答案