Filter object properties by key in ES6

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 that I have something like.

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

I'm looking for a clean way to do this with Es6, so the spread operators are available to me. Thank!

+184
filter ecmascript-6
Aug 03 '16 at 18:02
source share
19 answers

If you have a list of allowed values, you can easily save 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 (raw data), then
  2. Array.prototype.filter to select keys that are in the allowed list using
    1. Array.prototype.includes to make sure they are present
  3. Array.prototype.reduce to create a new object with only allowed properties.

This will make a shallow copy with the allowed properties (but will not copy the properties themselves).

You can also use the object distribution operator to create a series of objects without changing them (thanks 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 trivial purposes, if you want to remove unnecessary fields from the source data (which I would not recommend doing since it includes some ugly mutations), you can invert includes verification as follows:

 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 included this example to show a mutation-based solution, but I do not propose using it.

+358
Aug 03 '16 at 18:14
source share

If you're fine using ES6 syntax, I find that the cleanest way to do this is as indicated here and here :

 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 a key saved as a string:

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

In the latter case, [key] converted to item2 , but since you are using the const assignment, you need to specify a name for the assignment. _ represents the emission 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, ... 

This not only reduces your operation to a single line, but also does not require you to know what other keys (the ones you want to keep).

+62
Aug 26 '17 at 17:39 on
source share

The easiest way to find this 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) 
+35
Oct 31 '17 at 14:55
source share

Nothing that has been said before, except to combine some of the answers into a common 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); 
+17
Nov 22 '17 at 20:15
source share

Just another solution in one line of code .

I played with the Destruction 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); 
+15
Mar 17 '18 at 18:49
source share

You can add a universal ofilter (implemented using generic oreduce ) so you can easily filter objects in the same way as 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 } } ] ) 

Check 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 can be implemented in many ways. I decided to attach to Array.prototype.reduce inside oreduce but you could just as easily write all this from scratch

+9
Aug 03 '16 at 22:52
source share

Here's how I did it recently:

 const dummyObj = Object.assign({}, obj); delete dummyObj[key]; const target = Object.assign({}, {...dummyObj}); 
+7
Oct 23 '17 at 18:03
source share

ok how about this line

  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]}))); 
+6
Mar 04 '19 at 4:37
source share

Now you can make it shorter and simpler 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) ) ); 

more about: Object.fromEntries

+5
May 10 '19 at 16:20
source share

Speculation on ssube is responsible .

Here is 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 beauty of the ES6 arrow function is that you should not pass in allowed as a parameter.

+4
Jan 17 '18 at 5:22
source share

The answers here are definitely suitable, but they are a bit slow because they require looping through the whitelist for each property of the object. The solution below is much faster for large datasets because it only goes 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, {} ); } sanitize(data, whitelist) 
+3
May 11 '18 at 17:26
source share

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 not very clear, plus the with statement is not recommended ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with ).

+3
Aug 14 '18 at 6:09
source share

A simpler solution without using filter can be achieved using 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 },{}) 
+3
Sep 14 '18 at 5:37
source share

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

Instead, using a for...in loop to loop using the keys of the object, or cycling the allowed keys, and then composing a new object is ~ 50% more productive than .

 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 



but. Take a look at jsPerf for simple use case tests. Results will vary by browser.

+2
Apr 7 '18 at 12:41
source share
 const filteredObject = Object.fromEntries(Object.entries(originalObject).filter(([key, value]) => key !== uuid)) 
+1
Sep 21 '19 at 16:21
source share

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 name it like this:

 filteredObject(myData, ['item2']); //{item1: { key: 'sdfd', value:'sdfd' }, item3: { key: 'sdfd', value:'sdfd' }} 
0
Mar 04 '18 at 5:00
source share

This function will filter the object based on a list of keys, this is more efficient than the previous answer, since it does not need to use Array.filter before calling Reduce. therefore its O (n) unlike O (n + is filtered)

 function filterObjectByKeys (object, keys) { return Object.keys(object).reduce((accum, key) => { if (keys.includes(key)) { return { ...accum, [key]: object[key] } } else { return accum } }, {}) } 
0
Sep 19 '18 at 14:30
source share

During the loop, do not return anything when certain properties / keys are found 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> ); }); 
0
Apr 22 '19 at 5:12
source share

You can delete a special key 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; 
0
Aug 23 '19 at 12:59
source share



All Articles