362

Let's say I have an object:

{
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

I want to create another object by filtering the object above so I have something like.

 {
    item1: { key: 'sdfd', value:'sdfd' },
    item3: { key: 'sdfd', value:'sdfd' }
 }

I am looking for a clean way to accomplish this using Es6, so spread operators are available to me.

Henke
  • 1,466
  • 2
  • 9
  • 22
29er
  • 6,967
  • 12
  • 43
  • 59

29 Answers29

691

If you have a list of allowed values, you can easily retain them in an object using:

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.keys(raw)
  .filter(key => allowed.includes(key))
  .reduce((obj, key) => {
    obj[key] = raw[key];
    return obj;
  }, {});

console.log(filtered);

This uses:

  1. Object.keys to list all properties in raw (the original data), then
  2. Array.prototype.filter to select keys that are present in the allowed list, using
    1. Array.prototype.includes to make sure they are present
  3. Array.prototype.reduce to build a new object with only the allowed properties.

This will make a shallow copy with the allowed properties (but won't copy the properties themselves).

You can also use the object spread operator to create a series of objects without mutating them (thanks to rjerue for mentioning this):

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.keys(raw)
  .filter(key => allowed.includes(key))
  .reduce((obj, key) => {
    return {
      ...obj,
      [key]: raw[key]
    };
  }, {});

console.log(filtered);

For purposes of trivia, if you wanted to remove the unwanted fields from the original data (which I would not recommend doing, since it involves some ugly mutations), you could invert the includes check like so:

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

Object.keys(raw)
  .filter(key => !allowed.includes(key))
  .forEach(key => delete raw[key]);

console.log(raw);

I'm including this example to show a mutation-based solution, but I don't suggest using it.

ssube
  • 41,733
  • 6
  • 90
  • 131
  • 1
    Thanks that worked great. I also found an approach by using 'deconstruction syntax. IE : const {item1,item3} = raw const newObject = {item1,item3} – 29er Aug 03 '16 at 18:41
  • 2
    Deconstruction will work (just fine), but is purely compile-time. You can't make it a dynamic list of properties or provide any complex rules (a loop can have validation callbacks attached, for example). – ssube Aug 03 '16 at 18:43
  • yep exactly. your way is obviously the better approach for anything dynamic, thanks again – 29er Aug 03 '16 at 18:44
  • 3
    I can't vote this up enough! Well done for using filter and reduce and not constructing another object from a for loop. And awesome that you explicitly separated the immutable and mutable versions. +1 – Sukima Aug 03 '16 at 20:09
  • 3
    Quick warning: `Array.prototype.includes` is not part of ES6. It's introduced in ECMAScript 2016 (ES7). – Vineet Mar 10 '17 at 02:02
  • 3
    If you want to do the reduce in an immutable way, you could also replace the function contents with return { ...obj, [key]: raw[key] } – rjerue Feb 07 '18 at 18:57
  • @rjerue that's a good point. I'll update the answer to include object spread, unless you'd rather suggest it for the rep. :) – ssube Feb 07 '18 at 20:25
  • If you care about performance, check out my answer - https://stackoverflow.com/a/49707485/3966682. – d4nyll Apr 07 '18 at 12:43
  • 1
    Using a `filter` before the `reduce` slows down the operation. Instead, you can use a conditional within the `reduce`. This is ~50% faster. – d4nyll Apr 07 '18 at 12:44
  • Solid answer! Check out mine before for a bit more performance: https://stackoverflow.com/a/50297342/3614036 – Joey Grisafe May 11 '18 at 17:30
  • This is simply brilliant and clean code. Thank you for sharing! – eagercoder Aug 28 '18 at 20:20
  • Array.prototype.includes() has linear time complexity. If the list of allowed values is large, it's better to store them as keys in a dictionary/object instead and take advantage of the O(1) search time complexity. – jamix Jun 16 '19 at 13:34
  • `Object.entries` and `Object.fromEntries (less support)` would work like a charm too, also if worries about mutation could try `Object.clone` – Valen Sep 21 '20 at 17:14
130

If you are OK with using ES6 syntax, I find that the cleanest way to do this, as noted here and here is:

const data = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const { item2, ...newData } = data;

Now, newData contains:

{
  item1: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

Or, if you have the key stored as a string:

const key = 'item2';
const { [key]: _, ...newData } = data;

In the latter case, [key] is converted to item2 but since you are using a const assignment, you need to specify a name for the assignment. _ represents a throw away value.

More generally:

const { item2, ...newData } = data; // Assign item2 to item2
const { item2: someVarName, ...newData } = data; // Assign item2 to someVarName
const { item2: _, ...newData } = data; // Assign item2 to _
const { ['item2']: _, ...newData } = data; // Convert string to key first, ...

Not only does this reduce your operation to a one-liner but it also doesn't require you to know what the other keys are (those that you want to preserve).

A simple utility function would look like this:

function removePropFromObject(obj, prop) {
  const { [prop]: _, ...rest } = obj
  return { ...rest }
}
JaysQubeXon
  • 5,447
  • 3
  • 11
  • 15
Ryan H.
  • 5,418
  • 4
  • 34
  • 43
  • 5
    " `_` represents a throw away value" where does this come? First time I see it – yhabib Sep 22 '17 at 13:19
  • 6
    I believe this is an adopted convention by the JS community. An `_` is simply a valid variable name that can be used in JS but since it is pretty much nameless, it really shouldn't be used in that way if you care to convey intent. So, it's been adopted as a way to denote a variable you don't care about. Here's further discussion about it: https://stackoverflow.com/questions/11406823/underscore-as-a-javascript-variable – Ryan H. Sep 22 '17 at 13:29
  • 4
    This is much tidier than the accepted answer, avoids the overhead of creating a new array with Object.keys(), and the overhead of iterating the array with `filter` and `reduce`. – ericsoco Dec 16 '17 at 05:46
  • 3
    @yhabib the `_` doesn't matter, it's just a variable name, you can rename it to anything you want – Vic Feb 23 '18 at 21:33
  • awesome! i just came across this method and loving it :) – Lelouch May 28 '18 at 22:22
  • doesn't that create a `item2` global variable? – njzk2 Jun 11 '18 at 05:25
  • @njzk2 If you were to execute this code in the global space, yes, but that would be an odd thing to do in practice. Like any other variable you’d create, it should have the smallest practical scope. – Ryan H. Jun 11 '18 at 12:29
  • Can this be generalized to a list of keys to remove? – Gerrat Aug 14 '18 at 18:58
  • 1
    @Gerrat I don't think a generalized solution would be a trivial one-liner. For that, I would use lodash's `omit` function: https://lodash.com/docs/4.17.10#omit or one of the other solutions given here. – Ryan H. Aug 14 '18 at 19:27
  • Donig it with a list of keys only seems to work if you execute this in a loop that iterates over the keys one by one. That doesn't sound very efficient. Other than that, I really like this solution. – mcv Jun 12 '19 at 13:35
  • What if you only know they key you want to keep ( to filter a query for example ) ? In this example it would be item1 & item3 Can you do something like `const something { item1, item3 } = data` ? ( I know this code does not work but I'm wondering if deconstruction don't allow this with a syntax I don't know about ) – mel-mouk Dec 02 '19 at 10:49
  • 1
    @mel-mouk You can do this: `const { item1, item3, ..._ } = data` – Ryan H. Dec 02 '19 at 14:52
  • @ryan-h Yes I know about this one, I was wondering if it was possible to get this as an object, and not as a list of variable – mel-mouk Dec 04 '19 at 13:58
52

The cleanest way you can find is with Lodash#pick

const _ = require('lodash');

const allowed = ['item1', 'item3'];

const obj = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

const filteredObj = _.pick(obj, allowed)
Guy Segev
  • 1,489
  • 14
  • 21
47

Nothing that hasn't been said before, but to combine some answers to a general ES6 answer:

const raw = {
  item1: { key: 'sdfd', value: 'sdfd' },
  item2: { key: 'sdfd', value: 'sdfd' },
  item3: { key: 'sdfd', value: 'sdfd' }
};

const filteredKeys = ['item1', 'item3'];

const filtered = filteredKeys
  .reduce((obj, key) => ({ ...obj, [key]: raw[key] }), {});

console.log(filtered);
Roberto Bonvallet
  • 27,307
  • 5
  • 37
  • 57
Clemens Helm
  • 3,240
  • 1
  • 17
  • 13
38

You can now make it shorter and simpler by using the Object.fromEntries method (check browser support):

const raw = { item1: { prop:'1' }, item2: { prop:'2' }, item3: { prop:'3' } };

const allowed = ['item1', 'item3'];

const filtered = Object.fromEntries(
   Object.entries(raw).filter(
      ([key, val])=>allowed.includes(key)
   )
);

read more about: Object.fromEntries

Damon
  • 9,303
  • 14
  • 76
  • 136
dudi harush
  • 401
  • 4
  • 5
33

Just another solution in one line of Modern JS with no external libraries.

I was playing with "Destructuring" feature :

const raw = {
    item1: { key: 'sdfd', value: 'sdfd' },
    item2: { key: 'sdfd', value: 'sdfd' },
    item3: { key: 'sdfd', value: 'sdfd' }
  };
var myNewRaw = (({ item1, item3}) => ({ item1, item3 }))(raw);
console.log(myNewRaw);
Novy
  • 1,281
  • 10
  • 23
  • 2
    `var myNewRaw = (({ item1, item3}) => ({ item1, item3 }))(raw);` Syntax issue – Awol Mar 30 '18 at 07:09
  • 1
    There are a couple of things condensed here: First thing first, there is the declaration of the function. it is an arrow function (it takes an object and return an object) . It is the same thing as function(obj){return obj;}. the second thing is that ES6 allow destructuring future. In my function declaration I destructure my object{ item1, item3}. And the last thing is that I self invoke my function. You can use self invoke function to manage your scope for example. But here it was just to condense the code. I hope it is clear. If I miss something feel free to add more. – Novy Feb 06 '19 at 23:00
  • 6
    this is the preferred modern approach imho – mattdlockyer Jul 27 '19 at 15:34
  • I believe this will add keys that are missing in the original object. – charles-allen Aug 05 '20 at 06:15
  • What do you mean @AjahnCharles? Could you help me get your point please? – Novy Aug 05 '20 at 07:16
  • 1
    The [accepted answer](https://stackoverflow.com/a/38750895/2957169) will only include keys that are in the filter list AND exist in the original data. I believe your answer will insert missing keys with `undefined` as the value, for example if my original data didn't include `item3`, I think your code would add it. There might be use-cases where that's undesirable. (for my use-case it's fine! I'm using it!) – charles-allen Aug 05 '20 at 07:24
  • @Novy Thanks for this amazing answer. I've learned about self-invoking functions and destructuring today and thanks for that. There is 1 thing I do not understand why is the body of the arrow function wrapped in parentheses? this part after the arrow: ` => ({ item1, item3})`. I understand that parenthesis left of the arrow hold function parameters but I expected simple function { body } on the right side. Why do we need them or what are they called? I can't google them (they don't seem like the normal Grouping Paramemeter) – Nika Kasradze Oct 30 '20 at 09:15
  • 1
    @NikaKasradze without those parentheses the function will return undefined. Awol did help me with that point at the first time. And after reading blogs and read the specification I understand it better. It will try a brief explanation in another comment if you do not mind. – Novy Nov 01 '20 at 23:14
  • 1
    @NikaKasradze According to specification [Arrow Function syntax](http://www.ecma-international.org/ecma-262/6.0/#sec-arrow-function-definitions) is: ArrowParameters => ConciseBody and the ConciseBody : { FunctionBody } In our case With simply the brackets after the arrow the parser will see it as your conciseBody. >>>> next part coming – Novy Nov 01 '20 at 23:15
  • 1
    @NikaKasradze ... You also know if your arrow function is a one line expression you do not need to put explicitly the return keyword and you can drop the brackets . You have something like ArrowParameters => returnValue. If the return value is an object literal you have to force it as an an expression and the way to do it is to add these parentheses. I hope it is clearer for you. Sorry for my english by the way. – Novy Nov 01 '20 at 23:16
  • @NikaKasradze don't forget to upvote the solution if you find it usefull I mean only if you want. – Novy Nov 02 '20 at 11:47
13

ok, how about this one-liner

    const raw = {
      item1: { key: 'sdfd', value: 'sdfd' },
      item2: { key: 'sdfd', value: 'sdfd' },
      item3: { key: 'sdfd', value: 'sdfd' }
    };

    const filteredKeys = ['item1', 'item3'];

    const filtered = Object.assign({}, ...filteredKeys.map(key=> ({[key]:raw[key]})));
inabramova
  • 201
  • 3
  • 10
12

You can add a generic ofilter (implemented with generic oreduce) so you can easily filter objects the same way you can arrays –

const oreduce = (f, acc, o) =>
  Object
    .entries (o)
    .reduce
      ( (acc, [ k, v ]) => f (acc, v, k, o)
      , acc
      )

const ofilter = (f, o) =>
  oreduce
    ( (acc, v, k, o)=>
        f (v, k, o)
          ? Object.assign (acc, {[k]: v})
          : acc
    , {}
    , o
    )

We can see it working here -

const data =
  { item1: { key: 'a', value: 1 }
  , item2: { key: 'b', value: 2 }
  , item3: { key: 'c', value: 3 }
  }

console.log
  ( ofilter
      ( (v, k) => k !== 'item2'
      , data
      )
      // [ { item1: { key: 'a', value: 1 } }
      // , { item3: { key: 'c', value: 3 } }
      // ]

  , ofilter
      ( x => x.value === 3
      , data
      )
      // [ { item3: { key: 'c', value: 3 } } ]
  )

Verify the results in your own browser below –

const oreduce = (f, acc, o) =>
  Object
    .entries (o)
    .reduce
      ( (acc, [ k, v ]) => f (acc, v, k, o)
      , acc
      )

const ofilter = (f, o) =>
  oreduce
    ( (acc, v, k, o)=>
        f (v, k, o)
          ? Object.assign (acc, { [k]: v })
          : acc
    , {}
    , o
    )

const data =
  { item1: { key: 'a', value: 1 }
  , item2: { key: 'b', value: 2 }
  , item3: { key: 'c', value: 3 }
  }

console.log
  ( ofilter
      ( (v, k) => k !== 'item2'
      , data
      )
      // [ { item1: { key: 'a', value: 1 } }
      // , { item3: { key: 'c', value: 3 } }
      // ]

  , ofilter
      ( x => x.value === 3
      , data
      )
      // [ { item3: { key: 'c', value: 3 } } ]
  )

These two functions could be implemented in many ways. I chose to attach to Array.prototype.reduce inside oreduce but you could just as easily write it all from scratch

Thank you
  • 107,507
  • 28
  • 191
  • 224
  • I like your solution, but I don't know how much clearer / more efficient it is compared to [this one](http://stackoverflow.com/a/37616104/472610). – Jonathan H Mar 05 '17 at 09:47
  • 3
    Here is a [benchmark](https://jsperf.com/ed-3-vs-es-2015-vs-es-2016/1) showing that your solution is the fastest. – Jonathan H Mar 05 '17 at 11:47
  • In `oreduce`, the first `acc` is shadowed in `.reduce(acc, k)`, and in `ofilter` the `o` is shadowed - `oreduce` is called with a variable called `o` as well - which is which? – Jarrod Mosen Sep 27 '17 at 03:27
  • in `ofilter` the variable `o` is shadowed but it always points to the the same input var; that’s why its shadowed here, *because* it’s the same - the accumulator (`acc`) is also shadowed because it more clearly shows how the data moves thru the lambda; `acc` is not always the same *binding*, but it always represents the current *persistent* state of the computational result we wish to return – Thank you Sep 27 '17 at 16:21
  • While the code works well and the method is very good I do wonder what help writing code like that is to somebody obviously needing help with javascript. I'm all for brevity but that is almost as compact as a minimized code. – Paul G Mihai Nov 05 '18 at 20:33
9

This is how I did it, recently:

const dummyObj = Object.assign({}, obj);
delete dummyObj[key];
const target = Object.assign({}, {...dummyObj});
Rajat Saxena
  • 3,557
  • 4
  • 41
  • 57
  • 1
    Hm. It seems you're mixing old and new syntax. `Object.assign == ...` You could write `const dummyObj = { ...obj }` and `const target = { ...dummyObj }`. Plus, the latter is not at all necessary, since you could directly work with dummyObj afterwards. – Andy Dec 09 '19 at 22:04
  • This does *three* copies of an object. Just to only get one of those with the key removed: `dummyObj = Object.assign({}, obj)` - clone `obj` into a new object called `dummyObj`; `delete dummyObj[key];` - remove the key. At this point *your job is done*. But then: `{...dummyObj}` - clone `dummyObj` (which is already a clone) into a temporary object; ` target = Object.assign({}, {...dummyObj})` - clone the cloned temporary object (a clone of a clone) into a new object called `target`. – VLAZ May 27 '21 at 06:19
8

The answers here are definitely suitable but they are a bit slow because they require looping through the whitelist for every property in the object. The solution below is much quicker for large datasets because it only loops through the whitelist once:

const data = {
  allowed1: 'blah',
  allowed2: 'blah blah',
  notAllowed: 'woah',
  superSensitiveInfo: 'whooooah',
  allowed3: 'bleh'
};

const whitelist = ['allowed1', 'allowed2', 'allowed3'];

function sanitize(data, whitelist) {
  return whitelist.reduce(
    (result, key) =>
      data[key] !== undefined
        ? Object.assign(result, { [key]: data[key] })
        : result,
    {}
  );
}

const result = sanitize(data, whitelist);

console.log(result);
VLAZ
  • 18,437
  • 8
  • 35
  • 54
Joey Grisafe
  • 146
  • 2
  • 6
6

Piggybacking on ssube's answer.

Here's a reusable version.

Object.filterByKey = function (obj, predicate) {
  return Object.keys(obj)
    .filter(key => predicate(key))
    .reduce((out, key) => {
      out[key] = obj[key];
      return out;
    }, {});
}

To call it use

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

var filtered = Object.filterByKey(raw, key => 
  return allowed.includes(key));
});

console.log(filtered);

The beautiful thing about ES6 arrow functions is that you don't have to pass in allowed as a parameter.

alpay
  • 438
  • 7
  • 11
Evan Plaice
  • 13,310
  • 4
  • 70
  • 94
6

A simpler solution without using filter can be achieved with Object.entries() instead of Object.keys()

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.entries(raw).reduce((acc,elm)=>{
  const [k,v] = elm
  if (allowed.includes(k)) {
    acc[k] = v 
  }
  return acc
},{})
Itai Noam
  • 2,217
  • 2
  • 15
  • 11
6

Another solution using the Array.reduce method on the allowed keys:

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = allowed.reduce((obj, key) => { 
  obj[key] = raw[key]; 
  return obj 
}, {})

console.log(filtered);

Especially in case of larger source objects (raw in this example) it would make sense. The iteration will not be executed using all the entries of the source, but only using the keys you want to filter, thus shorter/faster...

Demonstration in this Fiddle...


But I do have to say I also like the solution in this answer here which is using Object.fromEntries Array.filter and Array.includes:

const object = Object.fromEntries(
  Object.entries(raw).filter(([key, value]) => allowed.includes(key))
);

Demonstration in this Fiddle...

Wilt
  • 33,082
  • 11
  • 129
  • 176
  • Wilt, your second approach is an exact duplicate of this answer provided last year: https://stackoverflow.com/a/56081419/5522000 – Art Schmidt Apr 05 '20 at 19:11
  • @ArtSchmidt Thank you for your comment: Missed that one in the long list. I will refer to that answer instead. – Wilt Apr 06 '20 at 07:45
  • What is "new" about `.reduce()`? I suppose this comment comes from the future but I don't think it was new in 2020, either. – VLAZ May 27 '21 at 06:23
  • @VLAZ, not sure why I wrote that at the time, maybe because some people even today still want to support IE8 and it won't work there. I removed the "new" from the answer... – Wilt May 27 '21 at 07:36
5

You can do something like this:

const base = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const filtered = (
    source => { 
        with(source){ 
            return {item1, item3} 
        } 
    }
)(base);

// one line
const filtered = (source => { with(source){ return {item1, item3} } })(base);

This works but is not very clear, plus the with statement is not recommended (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with).

Bouni
  • 545
  • 6
  • 12
  • This...is horrible. I'm aware `with` has its (very, very few) uses but this isn't one of them. It's just destructuring with extra steps. `source => { with(source){ return {item1, item3} } }` is equivalent to `({item1, item3}) => ({item1, item3})` [which is already an answer](https://stackoverflow.com/a/49340650/). – VLAZ May 27 '21 at 06:27
5

Simple Way! To do this.

const myData = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};
const{item1,item3}=myData
const result =({item1,item3})
  • You are not actually filtering anything here, just destructuring the data given. But what happens when the data changes? – Idris Dopico Peña May 20 '20 at 13:06
  • @IdrisDopicoPeña - The destructuring is the filter. How is an object of fieldnames any different to using an array of field names? (though this solution will add missing keys) – charles-allen Aug 05 '20 at 06:13
  • 1
    @charles-allen an array of field names can be changed more easily without requiring the code that uses it to change. So you can have a reusable function that takes that array and filters your object, e.g., `myFunc(["item1", "item3"])` can later be reused as `myFunc(["foo", "bar"])` without changing anything about how it works. With this approach you need different function for each object you want to filter the keys of. – VLAZ May 27 '21 at 06:30
  • @VLAZ - True. Maybe I misunderstood Idris. I thought they meant different `myData`, not a different filter (that is my use case -- I know what properties I need at compile time, so this solution is much sleaker). – charles-allen May 27 '21 at 08:09
  • @charles-allen I'm not saying this solution is wrong. It's indeed very useful. However, the question was what's the difference. If I needed to extract `item1` and `item3` one time and then `foo` and `bar` another time, I'd probably just go with destructuring twice. If I need to do it a lot more often than that or I don't even know which ones I want, then I'd go with a function. – VLAZ May 27 '21 at 08:12
  • @VLAZ - Completely agree with you! – charles-allen May 27 '21 at 21:15
3

There are many ways to accomplish this. The accepted answer uses a Keys-Filter-Reduce approach, which is not the most performant.

Instead, using a for...in loop to loop through keys of an object, or looping through the allowed keys, and then composing a new object is ~50% more performanta.

const obj = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const keys = ['item1', 'item3'];

function keysReduce (obj, keys) {
  return keys.reduce((acc, key) => {
    if(obj[key] !== undefined) {
      acc[key] = obj[key];
    }
    return acc;
  }, {});
};

function forInCompose (obj, keys) {
  const returnObj = {};
  for (const key in obj) {
    if(keys.includes(key)) {
      returnObj[key] = obj[key]
    }
  };
  return returnObj;
};

keysReduce(obj, keys);   // Faster if the list of allowed keys are short
forInCompose(obj, keys); // Faster if the number of object properties are low

a. See jsPerf for the benchmarks of a simple use case. Results will differ based on browsers.

d4nyll
  • 9,170
  • 5
  • 43
  • 59
3
const filteredObject = Object.fromEntries(Object.entries(originalObject).filter(([key, value]) => key !== uuid))
β.εηοιτ.βε
  • 16,236
  • 11
  • 41
  • 53
Konrad Albrecht
  • 799
  • 1
  • 4
  • 16
  • 2
    There are other answers that provide the OP's question, and they were posted some time ago. When posting an answer, please make sure you add either a new solution, or a substantially better explanation, especially when answering older questions. – help-info.de Sep 21 '19 at 17:00
3

I know that this already has plenty of answers and is a rather old question. But I just came up with this neat one-liner:

JSON.parse(JSON.stringify(raw, ['key', 'value', 'item1', 'item3']))

That returns another object with just the whitelisted attributes. Note that the key and value is included in the list.

wiktus239
  • 1,213
  • 1
  • 9
  • 29
  • Love this! Probably really quick execution, and it's easy to filter out one or more properties – Janis Jansen Apr 15 '21 at 12:45
  • @JanisJansen serialising and de-serialising an object doesn't seem very quick to me. Also, you'd lose values like functions, or `undefined`, or `NaN` or BigInts. – VLAZ May 27 '21 at 06:34
2

You can remove a spesific property on your object

items={
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

// Example 1
var key = "item2";
delete items[key]; 

// Example 2
delete items["item2"];

// Example 3
delete items.item2;
Esin ÖNER
  • 596
  • 6
  • 6
2

I'm surprised how nobody has suggested this yet. It's super clean and very explicit about which keys you want to keep.

const unfilteredObj = {a: ..., b:..., c:..., x:..., y:...}

const filterObject = ({a,b,c}) => ({a,b,c})
const filteredObject = filterObject(unfilteredObject)

Or if you want a dirty one liner:

const unfilteredObj = {a: ..., b:..., c:..., x:..., y:...}

const filteredObject = (({a,b,c})=>({a,b,c}))(unfilteredObject);
CCD White
  • 111
  • 1
  • 7
  • This method will add a key not present in the original array. Might be a problem or not, this should be at least pointed out. – ponchietto Apr 20 '20 at 18:11
  • I think this guy suggested it already: https://stackoverflow.com/a/49340650/2957169 – charles-allen Aug 05 '20 at 07:27
  • "*I'm surprised how nobody has suggested this yet.*" it's already been suggested [by Novy in November 2018](https://stackoverflow.com/a/49340650/) and [by ghanshyam bendkoli in December 2019](https://stackoverflow.com/a/59535105/). – VLAZ May 27 '21 at 06:39
2

Another short way

function filterByKey(v,keys){
  const newObj ={};
  keys.forEach(key=>{v[key]?newObj[key]=v[key]:''});
  return newObj;
}

//given
let obj ={ foo: "bar", baz: 42,baz2:"blabla" , "spider":"man", monkey:true};

//when
let outObj =filterByKey(obj,["bar","baz2","monkey"]);

//then 
console.log(outObj);
  //{
  //  "baz2": "blabla",
  //  "monkey": true
  //}
Adam111p
  • 2,529
  • 1
  • 20
  • 18
2

Many of the above solutions repeatedly call Array.prototype.includes for each key in raw, which will make the solution O(n·m) (where n is the number of keys in the object an m is the length of the allowed list).

This could be avoided by using an allowed Set, but iterating over the allowed keys and copying them to an initially-empty object gives very simple, readable code that is O(m):

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = {};
for (const key of allowed) {
  if (key in raw) filtered[key] = raw[key];
}

console.log(filtered);

You could also use raw.hasOwnProperty(key) instead of key in raw if you wanted to avoid copying inherited properties.

cpcallen
  • 1,251
  • 10
  • 22
1

OK, how about this:

const myData = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

function filteredObject(obj, filter) {
  if(!Array.isArray(filter)) {
   filter = [filter.toString()];
  }
  const newObj = {};
  for(i in obj) {
    if(!filter.includes(i)) {
      newObj[i] = obj[i];
    }
  }
  return newObj;
}

and call it like this:

filteredObject(myData, ['item2']); //{item1: { key: 'sdfd', value:'sdfd' }, item3: { key: 'sdfd', value:'sdfd' }}
Alireza
  • 83,698
  • 19
  • 241
  • 152
1

This function will filter an object based on a list of keys, its more efficient than the previous answer as it doesn't have to use Array.filter before calling reduce. so its O(n) as opposed to O(n + filtered)

function filterObjectByKeys (object, keys) {
  return Object.keys(object).reduce((accum, key) => {
    if (keys.includes(key)) {
      return { ...accum, [key]: object[key] }
    } else {
      return accum
    }
  }, {})
}
Khaled Osman
  • 794
  • 9
  • 14
1

The following method takes the object and any properties to filter out.

function removeObjectKeys(obj, ...keysToRemove) {
  let mObject = { ...obj }
  for (let key of keysToRemove) {
    const { [String(key)]: _, ...rest } = mObject
    mObject = { ...rest }
  }
  return mObject
}
    
const obj = { 123: "hello", 345: "world", 567: "and kitty" };
const filtered = removeObjectKeys(obj, 123);
console.log(filtered);

const twoFiltered = removeObjectKeys(obj, 345, 567);
console.log(twoFiltered);
JaysQubeXon
  • 5,447
  • 3
  • 11
  • 15
0

During loop, return nothing when certain properties/keys are encountered and continue with the rest:

const loop = product =>
Object.keys(product).map(key => {
    if (key === "_id" || key === "__v") {
        return; 
    }
    return (
        <ul className="list-group">
            <li>
                {product[key]}
                <span>
                    {key}
                </span>
            </li>
        </ul>
    );
});
Ryan Dhungel
  • 1,824
  • 1
  • 14
  • 22
0

Another approach would be to use Array.prototype.forEach() as

const raw = {
  item1: {
    key: 'sdfd',
    value: 'sdfd'
  },
  item2: {
    key: 'sdfd',
    value: 'sdfd'
  },
  item3: {
    key: 'sdfd',
    value: 'sdfd'
  }
};

const allowed = ['item1', 'item3', 'lll'];

var finalObj = {};
allowed.forEach(allowedVal => {
  if (raw[allowedVal])
    finalObj[allowedVal] = raw[allowedVal]
})
console.log(finalObj)

It includes values of only those keys which are available in the raw data and thus preventing adding any junk data.

Saksham
  • 8,110
  • 6
  • 35
  • 63
0

That would be my solution:

const filterObject = (obj, condition) => {
    const filteredObj = {};
    Object.keys(obj).map(key => {
      if (condition(key)) {
        dataFiltered[key] = obj[key];
      }
    });
  return filteredObj;
}
Анна
  • 749
  • 8
  • 19
0

use PropPick package


pick('item1 item3', obj);
// {
//   item1: { key: 'sdfd', value:'sdfd' },
//   item3: { key: 'sdfd', value:'sdfd' }
// }

RomuloVS
  • 1
  • 2