Lucas Fonseca Lucas Fonseca - 3 years ago 175
AngularJS Question

Lodash - filtering nested array, passing a function

I can't find a way to filter and extract only the itens in the nested arrays that match a specific criteria/expression

I've checked these links below but the solutions provided won't pass function to _.filter:

Find object by match property in nested array

lodash property search in array and in nested child arrays

Lodash - Search Nested Array and Return Object

So, let me explain it better. I currently have data that looks like this:
How can I retrieve the itens inside "listEvents" array for all objects that matchs an criteria?

[
{
"ModalidadeId": 1,
"Nome": "SOCCER",
"Ordem": "09",
"IconeId": "",
"listEvents": [
{
"EI": 2960542,
"No": "SÃO PAULO SP X ATLÉTICO LINENSE-SP",
"St": 1,
"Ini": "2017-09-30T10:00:00",
"MI": 1,
"CI": 251,
"TI": 4993,
"StAV": 0,
"De": false,
"Ics": [
"p22678",
"p22684"
],
"Ic": "",
"Tas": [],
"show": true,
"IniFormatada": "30/09/2017 às 10:00:00",
"MN": "FUTEBOL"
},
{
"EI": 3260915,
"No": "SÃO PAULO SP X ATLÉTICO LINENSE-SP",
"St": 0,
"Ini": "2017-09-30T10:00:00",
"MI": 1,
"CI": 251,
"TI": 4993,
"StAV": 0,
"De": false,
"Ics": [
"p29076",
"p22684"
],
"Ic": "",
"Tas": [],
"show": true,
"IniFormatada": "30/09/2017 às 10:00:00",
"MN": "FUTEBOL"
},
{
"EI": 430219,
"No": "NOROESTE SP X GREMIO NOVORIZONTINO SP",
"St": 0,
"Ini": "2017-09-30T15:00:00",
"MI": 1,
"CI": 251,
"TI": 2580,
"StAV": 0,
"De": false,
"Ics": [
"p31209",
"p31113"
],
"Ic": "",
"Tas": [],
"show": true,
"IniFormatada": "30/09/2017 às 15:00:00",
"MN": "FUTEBOL"
},
{
"EI": 443844,
"No": "COMERCIAL FC SP X BATATAIS FUTEBOL CLUBE SP",
"St": 0,
"Ini": "2017-09-30T15:00:00",
"MI": 1,
"CI": 251,
"TI": 2580,
"StAV": 0,
"De": false,
"Ics": [
"p31200",
"p31212"
],
"Ic": "",
"Tas": [],
"show": true,
"IniFormatada": "30/09/2017 às 15:00:00",
"MN": "FUTEBOL"
}
]
},
{
"ModalidadeId": 2,
"Nome": "TENIS",
"Ordem": "09",
"IconeId": "",
"listEvents": [
{
"EI": 2960542,
"No": "SÃO PAULO SP X ATLÉTICO LINENSE-SP",
"St": 1,
"Ini": "2017-09-30T10:00:00",
"MI": 1,
"CI": 251,
"TI": 4993,
"StAV": 0,
"De": false,
"Ics": [
"p22678",
"p22684"
],
"Ic": "",
"Tas": [],
"show": true,
"IniFormatada": "30/09/2017 às 10:00:00",
"MN": "FUTEBOL"
},
{
"EI": 3260915,
"No": "SÃO PAULO SP X ATLÉTICO LINENSE-SP",
"St": 0,
"Ini": "2017-09-30T10:00:00",
"MI": 1,
"CI": 251,
"TI": 4993,
"StAV": 0,
"De": false,
"Ics": [
"p29076",
"p22684"
],
"Ic": "",
"Tas": [],
"show": true,
"IniFormatada": "30/09/2017 às 10:00:00",
"MN": "FUTEBOL"
},
{
"EI": 430219,
"No": "NOROESTE SP X GREMIO NOVORIZONTINO SP",
"St": 0,
"Ini": "2017-09-30T15:00:00",
"MI": 1,
"CI": 251,
"TI": 2580,
"StAV": 0,
"De": false,
"Ics": [
"p31209",
"p31113"
],
"Ic": "",
"Tas": [],
"show": true,
"IniFormatada": "30/09/2017 às 15:00:00",
"MN": "FUTEBOL"
},
{
"EI": 443844,
"No": "COMERCIAL FC SP X BATATAIS FUTEBOL CLUBE SP",
"St": 0,
"Ini": "2017-09-30T15:00:00",
"MI": 1,
"CI": 251,
"TI": 2580,
"StAV": 0,
"De": false,
"Ics": [
"p31200",
"p31212"
],
"Ic": "",
"Tas": [],
"show": true,
"IniFormatada": "30/09/2017 às 15:00:00",
"MN": "FUTEBOL"
}
]
}
]


This is the code I've tried so far, but it doesn't seem to work.

_.filter($scope.listModalities, _.flow(
_.property('listEvents'),
_.partialRight(_.filter, function (o) {
var eventDate = new Date(o.Ini);
eventDate.setHours(eventDate.getHours() - 24);
var now = new Date();
return o.De == true || eventDate < now;
})
));

Answer Source

If you map to listEvents then flatten you can get rid of one iteration loop and get the results you want like so:

var now = new Date();
var listEvents = _.chain(input).map((o) => o.listEvents).flatten().filter((o)=> {
  if(o.De === true) return true;
  var eventDate = new Date(o.Ini);
  eventDate.setHours(eventDate.getHours() - 24);
  return eventDate < now;
}).value();

now = null;

Also, you'll notice that I moved the equality check o.De === true so that if it is true the function will return without extra computation. In addition, and also for efficiency, I moved the definition of now out of the iteration.

Here's a pen also.

In addition, here's what it would look like in es5.

var now = new Date();
var listEvents = _.chain(input).map(function (o) {
  return o.listEvents;
}).flatten().filter(function (o) {
  if (o.De === true) return true;
  var eventDate = new Date(o.Ini);
  eventDate.setHours(eventDate.getHours() - 24);
  return eventDate < now;
}).value();

And the pen to go with.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download