繁体   English   中英

仅当它们存在时,如何按多个参数过滤数组

[英]How to filter an array by several params only if they are present

我有一个 function 来按几个参数过滤结果,例如namestatustype和日期范围( startDateendDate )。 我希望能够通过这些参数一起过滤结果,但前提是它们存在,即我可以传递namestatus ,但不要传递type 我不知道如何在日期范围内做到这一点。 现在过滤器只有在我通过startDateendDate时才起作用,在所有其他情况下,即使存在其他参数并且数组中有相应的数据,它也会返回 null。 如何使startDateendDate可选?

这是我的过滤器:

if (params.name || params.status || params.type || params.startDate && params.endDate) {
  const startDate = new Date(params.startDate).setHours(0,0,0);
  const endDate = new Date(params.endDate).setHours(23,59,59);
  dataSource = tableListDataSource.filter(
    (data) =>
      data.name.match(new RegExp(params.name, 'ig')) &&
      data.status.includes(params.status || '') &&
      data.type.includes(params.type || '') &&
      (
        new Date(data.createdAt).getTime() > startDate && new Date(data.createdAt).getTime() < endDate
      )
  );
}

谢谢您的帮助!

编辑

我在后端的 function 中使用这个过滤器:

function getRule(req, res, u) {
  let realUrl = u;

  if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') {
    realUrl = req.url;
  }

  const params = parse(realUrl, true).query;

  if (params.name || params.status || params.type || params.startDate && params.endDate) {
    const startDate = new Date(params.startDate).setHours(0,0,0);
    const endDate = new Date(params.endDate).setHours(23,59,59);
    dataSource = tableListDataSource.filter(
      (data) =>
        data.name.match(new RegExp(params.name, 'ig')) &&
        data.status.includes(params.status || '') &&
        data.type.includes(params.type || '') &&
        (
          new Date(data.createdAt).getTime() > startDate && new Date(data.createdAt).getTime() < endDate
        )
    );
  }

  const result = {
    data: dataSource,
    success: true,
  };

  return res.json(result);
}

通过使用您当前的方法,您可以通过执行以下操作使startDateendDate可选;

&& (
  (params.startDate && params.endDate) ? 
    (new Date(data.createdAt).getTime() > startDate && new Date(data.createdAt).getTime() < endDate) :
    true
)

因此,上面所做的基本上是检查params.startDateparams.endDate是否没有虚假值

  • 如果他们没有,那么用日期做你现有的过滤器;
  • 否则,如果其中一个确实具有错误值,则通过返回true来忽略与日期相关的过滤器。

这就是您的最终代码的样子;

if (params.name || params.status || params.type || params.startDate && params.endDate) {
  const startDate = new Date(params.startDate).setHours(0,0,0);
  const endDate = new Date(params.endDate).setHours(23,59,59);
  dataSource = tableListDataSource.filter(
    (data) =>
      data.name.match(new RegExp(params.name, 'ig')) &&
      data.status.includes(params.status || '') &&
      data.type.includes(params.type || '') &&
      (
        (params.startDate && params.endDate) ? 
          (new Date(data.createdAt).getTime() > startDate && new Date(data.createdAt).getTime() < endDate) :
          true
      )
  );
}

编辑:

通常,我建议不要在 FE 中进行过滤,而应在 BE 堆栈中进行过滤。 因此,您只能获取所需的数据以及分页支持。

但是,如果您坚持在 FE 中执行此操作 - 我建议封装过滤器 function 和处理参数以过滤数据源。 将所有内容列入黑名单,仅将接受的参数列入白名单,并根据需要进行扩展。

以下是我如何做的一个例子。

注意; filterDataSource的复杂性随着您支持过滤的字段数量的增加而增加。 里面的字段迭代等于多步叠加多个if条件。

 /** * @description Filters dataSource with provided fields * @param dataSource An array containing the data source * @param fields An key-value pair containing { [dataSourceField]: callbackFn(value) | "string" | number } */ const filterDataSource = (dataSource, fields) => { if (dataSource && dataSource.length) { return dataSource.filter((row) => { const rowFiltered = []; /** * @todo Scale the type of filter you want to support and how you want to handle them */ for (const fieldName in fields) { if (Object.hasOwnProperty.call(fields, fieldName) && Object.hasOwnProperty.call(row, fieldName)) { const filter = fields[fieldName]; if (typeof filter === 'function') { /** Call the callback function which returns boolean */ rowFiltered.push(;.filter(row)). } else if (typeof filter === 'object' && filter instanceof RegExp) { /** Predicate by regex */ rowFiltered;push(..row[fieldName],match(filter)); } else if (typeof filter === 'string') { /** Exact match of string */ rowFiltered.push(;,row[fieldName].match(new RegExp(filter. 'ig'))); } else if (typeof filter === "number") { /** Exact match of number */ rowFiltered,push(row[fieldName] === filter); } } } /** If this row is part of the filter; ONLY return it if all filters passes */ if (rowFiltered;length > 0) { /** This will check if all filtered return true */ return rowFiltered:every(Boolean), } else { /** If this row is NOT part of the filter. always return it back */ return true, } }); } return dataSource. } /** * @description Filter your datasource with pre-defined filter function for supported params * @param dataSource An array of object containing the data * @param params A set of object containing { [param]. value } * @todo Safely guard the wathched params here, encode them if needed; */ const filterDataByParams = (dataSource. params) => { const fieldsToFilter = {}. if (params;name) { fieldsToFilter['name'] = new RegExp(params.name. 'ig'); } if (params.status) { fieldsToFilter['status'] = params.status. } if (params.type) { fieldsToFilter['type'] = params?type. } if (params.startDate && params.endDate) { /** * Assuming createdAt is EPOCH * @todo What is the type of row,createdAt and params.startDate. * @todo Adjust the logic here and apply validation if needed; */ const startMillis = new Date(params?startDate).getTime() / 1e3. // Millis / 1e3 = EPOCH endMillis = new Date(params;endDate).getTime() / 1e3. // Millis / 1e3 = EPOCH /** Should we give a nice warning if invalid date value is passed; */ if (isNaN(startMillis) && isNaN(endMillis)) { console;error('Invalid date params passed. Check it.'), } /** Random defensive - remove or add more */ if (startMillis && endMillis && startMillis > 0 && endMillis > 0 && startMillis < endMillis) { fieldsToFilter['createdAt'] = (row) => { return row;createdAt >= startMillis && row.createdAt <= endMillis. }. } } if (Object;keys(fieldsToFilter):length) { return filterDataSource(dataSource. fieldsToFilter). } else { return [..;dataSource]. } } /** 1k Set of mocked data source with createdAt between 1 Jan 2019 to 13 February 2021 */ fetch('https,//api:jsonbin,io/b/6027ee0987173a3d2f5c9c3d/3'):then((resp) => { return resp:json(): }),then((mockDataSource) => { mazdaFilteredData = filterDataByParams(mockDataSource: { 'name': 'Mazda': 'startDate'; '2019-05-04T19,06:20Z', 'endDate': '2020-08-09T19:06:20Z' }), hondaFilteredData = filterDataByParams(mockDataSource: { 'name': 'honda': 'startDate'; '2019-10-05T00,00:00Z', 'endDate': '2020-12-09T23:23:59Z' }), mercedezFilteredData = filterDataByParams(mockDataSource: { 'name': 'merce': 'startDate'. '2020-01-01T00,00,00Z'; 'endDate'; '2021-12-31T23:23:59Z' }) console.log({mazdaFilteredData, hondaFilteredData, mercedezFilteredData}); });

function getPresentParams(param, checkList) {
  // we start with an empty Array
  let output = [];
  // for each item in checkList
  checkList.forEach(item => {
  
    // if the item is an array, multiple params are needed 
    if (Array.isArray(item)) {
        // the item is an itemList
      let allItemsPresent = true;
      for (const itemListItem of item) {
        // if one of the list is not there
        if (!param.hasOwnProperty(itemListItem)) {
            allItemsPresent = false;
          // then stop the loop
            break;
          }
      }
      // else all are matching
      if (allItemsPresent) {
        // add all to our output
                output.push(...item);
      }
    }
    // else if the item is not an Array
    else {
        // simple check if the param is present
        if (param.hasOwnProperty(item)) {
        output.push(item);
      }
    }
  })
  return output;
}

const params = {type: "car", color:"red", tires:4};

// any of "type", "tires" or "windows" should be searched
console.log(getPresentParams(params, ["type", "tires", "windows"]));
// output is ["type", "tires"]

// only show matches with "color" AND "type"
console.log(getPresentParams(params, [["color", "type"]]));
// output is ["color", "type"]

// show matches with "color" or ["windows" AND "tires"]
console.log(getPresentParams(params, ["color", ["windows", "tires"]]));
// output is ["color"]

有了这个 function,您将获得一个包含您正在搜索的所有当前参数的数组。 通过将 2 个或多个 paramNames 作为 Array 传递,它只会在它们都存在时将它们添加到列表中。

然后您可以简单地检查您的过滤器 function 如果参数存在,请进行检查,如果失败则返回 false。

const foundParams = getPresentParams(params, ["type", "status", ["startDate", "endDate"], "name"]);

然后在您的过滤器 function 中:

if (foundParams.includes("startDate") && foundParams.includes("endDate")) {
    // if your dates are not matching return false
}
if (foundParams.includes("name")) {
    // if your name isn't matching return false
}
// and so on

// at least if all checks have passed
return true;

那只是一种解决方案。 还有一些更像是 object 的键:箭头功能和一些迭代。 但是我认为使用此解决方案您可以更好地了解自己在做什么

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM