Hedge
Hedge

Reputation: 16748

omit nested properties with Lodash

I'm trying to get rid of the properties 5MinuteRate and 15MinuteRatein the following object.

var object = { requestsPerSecond:
   { mean: 1710.2180279856818,
     count: 10511,
     'currentRate': 1941.4893498239829,
     '1MinuteRate': 168.08263156623656,
     '5MinuteRate': 34.74630977619571,
     '15MinuteRate': 11.646507524106095 } };

Lodash's omit()-function doesn't seem to work on nested objects. The following code doesn't work:

console.log(_.omit(object, 'requestsPerSecond.count'));

EDIT:

I tried this but it doesn't work quite right:

var subObject = _.omit(object.requestsPerSecond, '5MinuteRate', '15MinuteRate');

console.log(_.merge(object, subObject));

Upvotes: 16

Views: 37737

Answers (7)

AnandShiva
AnandShiva

Reputation: 1339

If you are like me trying to do this for omitBy which is not supporting nested filtering yet, you can use this following code

const inputObject = {
  operation: "category",
  params: {
    city: undefined,
    location: {
      latitude: undefined,
      value: "not undefined"

    },
  },
  id: "test_id___20200101000000000",
  crawler: "crawler_id",
  queue: "task_queue",
  job: "crawler_id_scheduler_platform",
  seedId: "test_id",
};

function removeUndefined(obj) {
  return _.omitBy(obj, _.isUndefined);
}

function deepRemoveUndefined(obj) {
  if (_.isObject(obj)) {
    return removeUndefined(
      _.mapValues(obj, (val) => (val && _.isObject(val) ? deepRemoveUndefined(val) : val))
    );
  }
  return obj;
}

const cleanedObject = deepRemoveUndefined(inputObject);

console.log(cleanedObject);

Upvotes: 0

Nick
Nick

Reputation: 181

I had the same issue but it wanted to omit all the named properties in a nested object.

Here's a generic function that would have worked for you also.

Just use it like this omit(object, ['name_1','name_2, ... ])

Function

// Variation on omit to recurse through objects and arrays
function omit(obj, arr) {
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (arr.includes(key)) {
        delete obj[key];
      } else if (Array.isArray(obj[key])) {
        for (let i = 0; i < obj[key].length; i++) {
          omit(obj[key][i], arr);
        }
      } else if (typeof obj[key] === 'object') {
        omit(obj[key], arr);
      }
    }
  }
  return obj;
}

var object = {
    requestsPerSecond: {
        mean: 1710.2180279856818,
        count: 10511,
        'currentRate': 1941.4893498239829,
        '1MinuteRate': 168.08263156623656,
        '5MinuteRate': 34.74630977619571,
        '15MinuteRate': 11.646507524106095
    }
};

object = omit(object, ['5MinuteRate','15MinuteRate']);
console.log(object);

and you should get a result like this

{
 "requestsPerSecond":
  {
    "mean": 1710.2180279856818,
    "count": 10511,
    "currentRate": 1941.4893498239828,
    "1MinuteRate": 168.08263156623656
  }
}

I would have liked to have used a later library I'm running test-cases inside Postman, so I'm limited in packages and versions.

Upvotes: 2

Danielo515
Danielo515

Reputation: 7061

If you are open to trying another library, partial.lenses has great support for all kind of operations on collections, including complex modifications like all the children of an object and so on.

So in your case it would be as simple as (L is just a shorthand for the import from partial.lesnes)

const newObject = L.remove(['requestsPerSecond','5MinuteRate'],object)

Now imagine that you have a different structure, where you have a set of nested properties with different names, but all with the same structure, and you want to target all of them. Imagine this example:

obj = { 
  requestsPerSecond: {
  first: {
    mean: 1710.2180279856818,
    count: 10511,
    '5MinuteRate': 34.74630977619571,
    '15MinuteRate': 11.646507524106095 
  }}
  second: {
    mean: 1710.2180279856818,
    count: 10511,
    '5MinuteRate': 34.74630977619571,
    '15MinuteRate': 11.646507524106095 
  }} 
};

In that case, it will be as simple as:

const newObject = L.remove(['requestsPerSecond',L.children,'5MinuteRate'],object)

Where L.children means to target all children of requestPerSecond.

Upvotes: 0

Claudiu
Claudiu

Reputation: 4109

Lodash _.omit works with nested objects. It appears that they improved the function since your question :)

object = _.omit(object, 'requestsPerSecond.5MinuteRate', 'requestsPerSecond.15MinuteRate');

UPDATE

omit will be removed from Lodash 5 onward

Upvotes: 7

Yuri Gor
Yuri Gor

Reputation: 1463

In case you need to omit some kind of paths deeply, here is an omitDeep from Deepdash:

obj = _.omitDeep(obj, /\.*5MinuteRate"\]$/);

note that this method will exclude all the matching paths at any depths. It supports a single path or array, represented as a constant value(s) or as a regex(es).

In the case of a string path given as an argument, each path in the object will be checked to end with given criteria. here is a more detailed codepen for your case

(Answer updated to fit most recent Deepdash v3.1.0)

Upvotes: 2

aemonge
aemonge

Reputation: 2347

Use unset: https://lodash.com/docs#unset , it gets cleaner:

var obj = { 
  requestsPerSecond: { 
    mean: 1710.2180279856818,
    count: 10511,
    'currentRate': 1941.4893498239829,
    '1MinuteRate': 168.08263156623656,
    '5MinuteRate': 34.74630977619571,
    '15MinuteRate': 11.646507524106095 
  } 
};

_.forEach(['requestsPerSecond.5MinuteRate', 'requestsPerSecond.15MinuteRate'], 
  function(omitProperty) {
    obj = _.unset(obj, omitProperty);
  }
);

// Or avoiding the "extra" loop.
obj = _.unset(obj, 'requestsPerSecond.5MinuteRate');
obj = _.unset(obj, 'requestsPerSecond.15MinuteRate');

Upvotes: 7

J. Titus
J. Titus

Reputation: 9690

You were almost there. Just assign what would be the result of your subObject to object.requestsPerSecond.

var object = {
  requestsPerSecond: {
    mean: 1710.2180279856818,
    count: 10511,
    'currentRate': 1941.4893498239829,
    '1MinuteRate': 168.08263156623656,
    '5MinuteRate': 34.74630977619571,
    '15MinuteRate': 11.646507524106095
  }
};

object.requestsPerSecond = _.omit(object.requestsPerSecond, '5MinuteRate', '15MinuteRate');

console.log(object);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>

Upvotes: 15

Related Questions