PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Tuesday, November 22, 2022

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

 November 22, 2022     arrays, data-structures, filtering, javascript, multiple-conditions     No comments   

Issue

I have a filter object that is returned by query params

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

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

I then have an array of objects that come in from a socket.

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

I want to filter out the objects that match the filters but the query obj isn't friendly enough to just map the arr through.

With the query obj shared above, i should return the objects id:1 and id:2 and id:4 from arr, since those object meet the criteria of sms, voicemail, & missed

I assume i need a modified query obj that has to have various conditions available for each property, i.e calls: voicemail === callDetails.voicemail === true or calls: received === callDetails.answered === true

I've seen lots of examples on how to filter an array of objects with multiple match-criteria, but with the req of the property having multiple conditions, i've hit a wall.

thanks for the help


Solution

The main idea is to provide kind of a rosetta stone which does bridge/map the query specific syntax with any list item's specific data structure. Thus one will end up writing a map which takes a query's structure into account but ensures for each necessary query endpoint an item specific filter condition/function.

The query function should simply filter the item list by applying a list of logical OR conditions, thus using some for returning the boolean filter value.

Which leaves one of implementing a helper method which collects ... via Object.entries and Array.prototype.flatMap as well as via String.prototype.split and Array.prototype.map ... the function endpoints from the above introduced requirements configuration/map, based on the query object, provided by the system. Thus this helper might be named 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; }



Answered By - Peter Seliger
Answer Checked By - Timothy Miller (PHPFixing Admin)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing