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;
            })
          ));
2
  • 1
    Provide an example of a criteria and the output after filtering using that criteria. Commented Sep 30, 2017 at 1: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 Commented Sep 30, 2017 at 2:53

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

5 Comments

How a ES5 implementation would be?
Hi @LucasFonseca, I added it ^
You could replace the map and flatten with flatMap('listEvents') making use of the property iteratee.
@GruffBunny thanks for the suggestion, I learned something. Got to love lodash!
Man you put a lot of effort into this answer, had to + 1
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);
     }
  })
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.