0

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;
            })
          ));
  • 1
    Provide an example of a criteria and the output after filtering using that criteria. – ibrahim mahrir Sep 30 '17 at 01:17
  • do you need the result to have nested object alone or do you need to the result to have parent object too ? a sample output would of great help – user93 Sep 30 '17 at 02:53

2 Answers2

1

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.

Also, as was suggested in the comments, you can save another step with flatMap:

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

console.log(listEvents);

pen

Josh Bowling
  • 313
  • 3
  • 10
1

Maybe you can try vanilla javascript way

var listEvents = []

myData.forEach((item) => {
item.listEvents.forEach((event) => {
     var eventDate = new Date(event.Ini);
     eventDate.setHours(eventDate.getHours() - 24);
     var now = new Date();
     if(event.De == true || eventDate < now){
        listEvents.push(event);
     }
  })
})
prabhatojha
  • 1,925
  • 17
  • 30