Sherry
Sherry

Reputation: 135

Lodash to filter out an array of objects

I am trying to filter out a nested array of objects using lodash which is pretty straightforward but I am looking to avoid multiple calls.

I am looking to create 2 array of objects using a single lodash call/function. Looking to find object property "$isMultiAccount" if it exists put the whole object into one result set and if not put it to another ruleset.

Currently I am doing this with Lodash "has and filter" for first and for other "!has" which means same object is looped twice , as object is relatively large its creating bottleneck for speed

https://repl.it/repls/HomelyExpensiveTruetype

const item = {
  "domains": [
    {
      "id": "dm11022",
      "information":{
        "description": "Customer",
        "owner": {
          "primary":{
            "name": "James",
            "phone": "NA"
          },
          "others": [
            {
              "$isMultiAccount": "./Yes"
            }
          ]
        }
      }
    },
    {
      "id": "dm12022",
      "information":{
        "description": "Customer",
        "owner": {
          "primary":{
            "name": "James",
            "phone": "NA"
          },
          "others": [
            {
              "$isMultiAccount": "./No"
            }
          ]
        }
      }
    },
    {
      "id": "dm12022",
      "information":{
        "description": "Customer",
        "owner": {
          "primary":{
            "name": "James",
            "phone": "NA"
          },
          "others": [
            {
              "conf": {
                  "isVpnBased":{
                    "accountType": "Primary"
                  }
              }
            }
          ]
        }
      }
    }


  ]
}
/*
Expected result
  output1 = [
        {
      "id": "dm11022",
      "information":{
        "description": "Customer",
        "owner": {
          "primary":{
            "name": "James",
            "phone": "NA"
          },
          "others": [
            {
              "$isMultiAccount": "./Yes"
            }
          ]
        }
      }
    },
    {
      "id": "dm12022",
      "information":{
        "description": "Customer",
        "owner": {
          "primary":{
            "name": "James",
            "phone": "NA"
          },
          "others": [
            {
              "$isMultiAccount": "./No"
            }
          ]
        }
      }
    }
  ]

// $isMultiAccount account do not exist in this object
 output2 = [
       {
      "id": "dm12022",
      "information":{
        "description": "Customer",
        "owner": {
          "primary":{
            "name": "James",
            "phone": "NA"
          },
          "others": [
            {
              "conf": {
                  "isVpnBased":{
                    "accountType": "Primary"
                  }
              }
            }
          ]
        }
      }
    }
 ]


 */

Upvotes: 0

Views: 261

Answers (3)

abuduba
abuduba

Reputation: 5042

Unfortunately, you have to iterate over the domains array as well ass on the owner.others array to determine if the object with specific key sits inside.

So the algorithm has O(n*m) complexity.

If you ask for a lodash function seems that the partition method is what you're looking for

As docs says:

Creates an array of elements split into two groups, the first of which contains elements predicate returns truthy for, the second of which contains elements predicate returns falsey for. The predicate is invoked with one argument: (value).

So it will be like:

_.partition(
  item.domains,
  e => _.some(
    _.get(e, 'information.owner.others'),
    el => _.has(el,"$isMultiAccount")
  )
);

Watch out - some hack available!

However, if the you're 100% sure that the element you're looking for will be always at specific index (for example it is supposed to be always as first element - so index 0) you can limit the algorithm to have linear complexity O(n) as only the size of the domains array will matter in terms of performance.

The hackish solution assuming fixed array index=0:

_.partition(
  item.domains,
  e => _.has(e, 'information.owner.others.0.$isMultiAccount')
);

NOTE Using lodash makes code a bit easier to read but of course it creates some performance overhead anyway.

Upvotes: 0

Bilal Siddiqui
Bilal Siddiqui

Reputation: 3629

Since item.domains.information.owner.others is an array, you need to tackle it as follows:

let multi = []; 
let notMulti = [];
_.each(item.domains, function (obj) {
   if (obj.information.owner.others.length && _.has(obj.information.owner.others[0], '$isMultiAccount'))
      multi.push(obj);
   else
      notMulti.push(obj);
});
console.log(multi);
console.log(notMulti);

Upvotes: 0

th3n3wguy
th3n3wguy

Reputation: 3737

const item = {
"domains": [
{
  "id": "dm11022",
  "information":{
    "description": "Customer",
    "owner": {
      "primary":{
        "name": "James",
        "phone": "NA"
      },
      "others": [
        {
          "$isMultiAccount": "./Yes"
        }
      ]
    }
  }
},
{
  "id": "dm12022",
  "information":{
    "description": "Customer",
    "owner": {
      "primary":{
        "name": "James",
        "phone": "NA"
      },
      "others": [
        {
          "$isMultiAccount": "./No"
        }
      ]
    }
  }
},
{
  "id": "dm12022",
  "information":{
    "description": "Customer",
    "owner": {
      "primary":{
        "name": "James",
        "phone": "NA"
      },
      "others": [
        {
          "conf": {
              "isVpnBased":{
                "accountType": "Primary"
              }
          }
        }
      ]
    }
  }
}
]
}
const [areMulti, areNotMulti] = _.reduce(item.domains, (current, next) => {
  return _.has(next, ‘information.owner.others.$isMultiAccount’)
    ? [current[0].concat(next), current[1]]
    : [current[0], current[1].concat(next)];
}, [[], []]);
console.log(areMulti);
console.log(areNotMulti);

Upvotes: 1

Related Questions