NDBoost
NDBoost

Reputation: 10634

iterate over array of objects and filter out not matching

i am trying to figure out the best lodashy way to do some object iteration/mutation. I am trying to find all "sids" which have servers that have a role of "DB". expected result would be a variable which has the full props (tier, sidadm, sid, orasid, servers) of any SIDs which have servers which have role DB.

data

var landscape = [
  {
    "tier": "production", 
    "sidadm": "ptpadm", 
    "sid": "PTP", 
    "orasid": "oraptp", 
    "servers": [
      {
        "hostname": "testep00", 
        "roles": ["DB"]
      }, 
      {
        "hostname": "testep01", 
        "roles": ["DG"]
      }, 
      {
        "hostname": "testep02", 
        "roles": ["SAPMS"]
      }, 
      {
        "hostname": "testep03", 
        "roles": ["SAPDI"]
      }, 
      {
        "hostname": "testep04", 
        "roles": ["SAPDI"]
      }, 
      {
        "hostname": "testep05", 
        "roles": ["SAPDI"]
      }, 
      {
        "hostname": "testep06", 
        "roles": ["SAPDI"]
      }
    ]
  },  
  {
    "tier": "techsandbox", 
    "sidadm": "bwzadm", 
    "sid": "BWZ", 
    "orasid": "orabwz", 
    "servers": [
      {
        "hostname": "testbw80", 
        "roles": ["DB"]
      }, 
      {
        "hostname": "testbw81", 
        "roles": ["DG"]
      }, 
      {
        "hostname": "testbw82", 
        "roles": ["SAPMS"]
      }, 
      {
        "hostname": "testbw83", 
        "roles": ["SAPDI"]
      }
    ]
  }, 
  {
    "tier": "techsandbox", 
    "sidadm": "eczadm", 
    "sid": "ECZ", 
    "orasid": "oraecz", 
    "servers": [ 
      {
        "hostname": "testec81", 
        "roles": ["DG"]
      }, 
      {
        "hostname": "testec82", 
        "roles": ["SAPDI", "SAPMS"]
      }
    ]
  }
];

This is what I have so far it works kinda, but doesn't exclude the SIDs which have empty server props. There has to be a better way of writing this with lodash, right?

// find me all SIDs with role "DB",
// should filter landscape and only return sids which have servers role=DB
// also should only contain the servers which are role=DB
var ls = _.extend({}, landscape);
_.each(ls, function (sid) {
  var servers = _.filter(sid.servers, function (server) {
    return _.contains(server.roles, 'DB');
  });
  // still need to strip out SID objects which have empty servers prop
  sid.servers = servers;
});
console.log('sids1() ::', ls);

Upvotes: 0

Views: 51

Answers (1)

Felix Kling
Felix Kling

Reputation: 816334

Just a simple filter + some should suffice:

var result = landscape.filter(function(sid) {
  return sid.servers.some(function(server) {
    return server.roles.indexOf("DB") > -1;
  });
});

Lodash provides implementations for both of these if you prefer it.

If you want to also only include servers with that specific role, you can map and filter:

var result = landscape
  .map(function(sid) {
    return Object.assign( // "clone" object
      {},
      sid,
      {
        servers: sid.servers.filter(function(server) {
          return server.roles.indexOf("DB") > -1;
        })
      }
    );
  })
  .filter(function(sid) {
    return sid.servers.length > 0;
  });

This can also be combined into a single reduce or use a simple forEach:

var result = [];
landscape.forEach(function(sid) {
  var servers = sid.servers.filter(function(server) {
    return server.roles.indexOf("DB") > -1;
  });
  if (servers.length > 0) {
    result.push(Object.assign({}, side, {servers: servers});
  }
});

Upvotes: 1

Related Questions