首页 > 解决方案 > 如何根据新计算的查询数据为数组项创建自定义过滤条件?

问题描述

我有一个由查询参数返回的过滤器对象

url = /all?channels=calls,text&calls=voicemail,missed

const query = {
  channels: 'calls,texts',
  calls: 'voicemail,missed',
};

然后我有一组来自套接字的对象。

const arr = [
  {
    id: 1,
    channel: 'SMS',
    sent: '2021-08-22T03:21:18.41650+0000',
    sender: {
      contactType: 'business',
    },
    recipients: [
      {
        contactType: 'corporate',
      },
    ],
    direction: 'INBOUND',
  },
  {
    id: 2,
    channel: 'VOICE',
    sent: '2021-08-20T23:15:56.00000+0000',
    sender: {
      contactType: 'business',
    },
    recipients: [
      {
        contactType: 'corporate',
      },
    ],
    callDetails: {
      answered: false,
      voicemail: true,
    },
    direction: 'INBOUND',
  },
  {
    id: 3,
    channel: 'VOICE',
    sent: '2021-08-20T23:15:56.00000+0000',
    sender: {
      contactType: 'business',
    },
    recipients: [
      {
        contactType: 'corporate',
      },
    ],
    callDetails: {
      answered: true,
      voicemail: false,
    },
    direction: 'INBOUND',
  },
  {
    id: 4,
    channel: 'VOICE',
    sent: '2021-08-20T23:15:56.00000+0000',
    sender: {
      contactType: 'business',
    },
    recipients: [
      {
        contactType: 'corporate',
      },
    ],
    callDetails: {
      answered: false,
      voicemail: false,
    },
    direction: 'INBOUND',
  },
];

我想过滤掉与过滤器匹配的对象,但queryobj 不够友好,无法仅映射arr

使用上面共享的查询 obj ,我应该返回对象id:1andid:2id:4from arr,因为这些对象符合sms, voicemail, & missed

我假设我需要一个修改后的查询 obj,它必须为每个属性提供各种条件,即calls: voicemail === callDetails.voicemail === truecalls: received === callDetails.answered === true

我已经看过很多关于如何过滤具有多个匹配条件的对象数组的示例,但是由于属性的 req 具有多个条件,所以我碰壁了。

谢谢您的帮助

标签: javascriptarraysdata-structuresfilteringmultiple-conditions

解决方案


主要思想是提供一种罗塞塔石碑,它可以将query特定语法与任何列表项的特定数据结构进行桥接/映射。因此,最终将编写一个映射,该映射将query' 结构考虑在内,但确保每个必要的查询端点都有一个项目特定的过滤条件/功能。

查询函数应该filter通过应用逻辑 OR 条件列表来简单地列出项目列表,从而some用于返回布尔过滤器值。

剩下的就是实现一个辅助方法,该方法基于系统提供的对象,从上面介绍的配置/映射中收集...通过Object.entriesArray.prototype.flatMap以及通过String.prototype.splitArray.prototype.map...功能端点。因此这个助手可能被命名为.requirementsqueryresolveQuery

const sampleList = [{
  id: 1,
  channel: 'SMS',

  direction: 'INBOUND',
}, {
  id: 2,
  channel: 'VOICE',

  callDetails: {
    answered: false,
    voicemail: true,
  },
  direction: 'INBOUND',
}, {
  id: 3,
  channel: 'VOICE',

  callDetails: {
    answered: true,
    voicemail: false,
  },
  direction: 'INBOUND',
}, {
  id: 4,
  channel: 'VOICE',

  callDetails: {
    answered: false,
    voicemail: false,
  },
  direction: 'INBOUND',
}];

// prepare a `requirements` map which ...
// - on one hand maps `query`-syntax to a list items's structure
// - and on the other hand does so by providing an item specific
//   filter condition/function for each necessary query endpoint.
const requirements = {
  channels: {
    texts: item => item.channel === 'SMS',
  },
  calls: {
    voicemail: item => item.channel === 'VOICE' && !!item.callDetails.voicemail,
    missed: item => item.channel === 'VOICE' && !item.callDetails.answered,
  },
}
// const query = {
//   channels: 'calls,texts',
//   calls: 'voicemail,missed',
// };

function resolveQuery(requirements, query) {
  const reject = item => false;

  // create/collect a list of filter condition/functions
  // which later will be applied as logical OR via `some`.
  return Object

    .entries(query)
    .flatMap(([ groupKey, groupValue ]) =>
      // e.g groupKey => 'channels',
      // groupValue => 'calls,texts'
      groupValue
        .split(',')
        .map(requirementKey =>
          // e.g requirementKey => 'calls'
          // or requirementKey => 'texts'
          requirements?.[groupKey]?.[requirementKey?.trim()] ?? reject
        )
    );
}

function queryFromItemList(itemList, requirements, query) {
  const conditionList = resolveQuery(requirements, query);

  console.log(
    'conditionList ... [\n ',
    conditionList.join(',\n  '),
    '\n]'
  );

  return itemList.filter(item =>
    conditionList.some(condition => condition(item))
  );
}

console.log(
  queryFromItemList(sampleList, requirements, {
    channels: 'calls,texts',
    calls: 'voicemail,missed',
  })
);
.as-console-wrapper { min-height: 100%!important; top: 0; }


推荐阅读