如何根据新计算的查询数据为数组项创建自定义过滤条件?

How does one create custom filter conditions for array items upon ever newly computed query-data?

我有一个由查询参数 return 编辑的过滤器对象

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',
  },
];

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

使用上面共享的查询对象,我应该 return 来自 arr 的对象 id:1id:2 以及 id:4,因为这些对象满足sms, voicemail, & missed

的标准

我假设我需要一个修改后的查询对象,它必须具有可用于每个 属性 的各种条件,即 calls: voicemail === callDetails.voicemail === truecalls: received === callDetails.answered === true

我看过很多关于如何使用多个匹配条件过滤对象数组的示例,但是由于 属性 的请求具有多个条件,我遇到了困难。

感谢帮助

主要思想是提供一种 rosetta stone,它 bridge/map query 具体任何列表项的特定数据结构的语法。因此,最终将编写一个映射,该映射考虑了 query 的结构,但确保为每个必要的查询端点提供一个特定于项目的过滤器 condition/function.

查询函数应该简单地 filter the item list by applying a list of logical OR conditions, thus using some 返回布尔过滤器值。

剩下的就是实现一个辅助方法,它收集... 通过Object.entries and Array.prototype.flatMap as well as via String.prototype.split and Array.prototype.map ...上面介绍的函数端点requirements configuration/map,基于系统提供的query对象。因此这个助手可能被命名为 resolveQuery.

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; }