Eduardo Jastre
Eduardo Jastre

Reputation: 65

Recursively filter array of objects with different properties

I have a object with others arrays. I need to filter when in the main array match RazaoSocial:"AAS" or Produtos:[{Descricao:"AAS"}]

That's my code:

var input = [
  {
    RazaoSocial: 'AAS',
    Produtos: [
    { DescricaoProduto: 'XXX', id:12, other:"other text" },
      { DescricaoProduto: 'YYY', id:12, other:"other text" }
    ]
  },
  {
    RazaoSocial: 'I found you',
    Produtos: [
      { DescricaoProduto: 'AAS', id:12, other:"other text" },
      { DescricaoProduto: 'Miss8', id:12, other:"other text" },
      { DescricaoProduto: 'Miss8', id:12, other:"other text" },
      { DescricaoProduto: 'Miss8', id:99, other:"other text" }      
    ]
  },
  {
    RazaoSocial: 'bla',
    Produtos: [
        { DescricaoProduto: 'AB', id:12, other:"other text" },
        { DescricaoProduto: 'CD', id:12, other:"other text" },
    ]
  },  
];

var res = input.filter(function f(o) {
    if (o.RazaoSocial.includes("AAS")) return true
    if (o.Produtos.DescricaoProduto) {
        console.log(o.Produtos);
        return (o.Produtos = o.Produtos.filter(f)).length
    }
})
 console.log(JSON.stringify(res, null, 2));

//result

[
  {
    "RazaoSocial": "AAS",
    "Produtos": [
      {
        "DescricaoProduto": "XXX",
        "id": 12,
        "other": "other text"
      },
      {
        "DescricaoProduto": "YYYAAS",
        "id": 12,
        "other": "other text"
      }
    ]
  }
]

Why the object with "i found you" it's not returned ? I was expeting

[
        {
            RazaoSocial: 'AAS',
            Produtos: [
                { DescricaoProduto: 'XXX', id: 12, other: "other text" },
                { DescricaoProduto: 'YYY', id: 12, other: "other text" }
            ]
        },
        {
            RazaoSocial: 'I found you',
            Produtos: [
                { DescricaoProduto: 'AAS', id: 12, other: "other text" },
                { DescricaoProduto: 'Miss8', id: 12, other: "other text" },
                { DescricaoProduto: 'Miss8', id: 12, other: "other text" },
                { DescricaoProduto: 'Miss8', id: 99, other: "other text" }
            ]
        }
    ]

I tried the examples in, but with no success. Recursively filter array of objects

What I'm doing wrong ?

thanks for the help.

Upvotes: 0

Views: 1251

Answers (3)

gotomanners
gotomanners

Reputation: 7926

The main problem with the original attempt was the if (o.Produtos.DescricaoProduto) {

o.Produtos is an array so you cannot access o.Produtos.DescricaoProduto without first getting an index.

So since o.Produtos is an array we can go ahead and filter it like we did the original input.

I've added both a recursive and non-recursive approach you could compare.

The recursive solution is entirely generic and can find any given value.

var input = [
  {
    RazaoSocial: 'AAS',
    Produtos: [
      { DescricaoProduto: 'XXX', id:12, other:"other text" },
      { DescricaoProduto: 'YYY', id:12, other:"other text" }
    ]
  },
  {
    RazaoSocial: 'I found you',
    Produtos: [
      { DescricaoProduto: 'AAS', id:12, other:"other text" },
      { DescricaoProduto: 'Miss8', id:12, other:"other text" },
      { DescricaoProduto: 'Miss8', id:12, other:"other text" },
      { DescricaoProduto: 'Miss8', id:99, other:"other text" }      
    ]
  },
  {
    RazaoSocial: 'bla',
    Produtos: [
        { DescricaoProduto: 'AB', id:12, other:"other text" },
        { DescricaoProduto: 'CD', id:12, other:"other text" },
    ]
  },  
];

var useRecursive = true, 
    res;
if (useRecursive) {
  var findValue = function (str) {
      return function(o) {
          return Object.values(o).filter(function (value) {
              if (Array.isArray(value)) {
                  return value.filter(findValue(str)).length > 0
              } else {
                  return value.toString().includes(str)
              }
          }).length > 0;
      };
  };
  res = input.filter(findValue("AAS"))

} else {
  res = input.filter(function f(o) {
    if (o.RazaoSocial.includes("AAS")) return true
    if (o.Produtos.length) {
        return o.Produtos.filter(function(o1) {
          return o1.DescricaoProduto.includes("AAS");
        }).length;
    }
  })
}
console.log(JSON.stringify(res, null, 2));

Upvotes: 2

see sharper
see sharper

Reputation: 12035

No recursion needed here. Use a simple filter something like:

var res = input.filter(function (o) {
 return o.RazaoSocial.includes("AAS") ||
   o.Produtos && o.Produtos.find(function (p) {
     return p.DescricaoProduto === 'AAS';
 }));
console.log(JSON.stringify(res, null, 2));

At least I think that's what you're after! It should leave you with all the objects in the array where RazaoSocial matches 'AAS' or any of the Produtos have DescriaoProduto == 'AAS'.

Upvotes: 0

Janaka Dissanayake
Janaka Dissanayake

Reputation: 547

var res = input.map(function f(o) {
var _ret = false;
if (o.RazaoSocial.includes("AAS")) _ret  = true
if (o.Produtos.DescricaoProduto) {
    console.log(o.Produtos);
    _ret  = (o.Produtos = o.Produtos.filter(f)).length
}
return _ret; 
})

I haven't test this make use of above

Upvotes: 1

Related Questions