[filter] 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 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.

This question is related to filter ecmascript-6

The answer is


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 }
}

const filteredObject = Object.fromEntries(Object.entries(originalObject).filter(([key, value]) => key !== uuid))

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]})));

Another solution using the "new" Array.reduce method:

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);

Demonstration in this Fiddle...


But I 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...


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);

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

_x000D_
_x000D_
const raw = {_x000D_
  item1: { key: 'sdfd', value: 'sdfd' },_x000D_
  item2: { key: 'sdfd', value: 'sdfd' },_x000D_
  item3: { key: 'sdfd', value: 'sdfd' }_x000D_
};_x000D_
_x000D_
const filteredKeys = ['item1', 'item3'];_x000D_
_x000D_
const filtered = filteredKeys_x000D_
  .reduce((obj, key) => ({ ...obj, [key]: raw[key] }), {});_x000D_
_x000D_
console.log(filtered);
_x000D_
_x000D_
_x000D_


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
    }
  }, {})
}

This is how I did it, recently:

const dummyObj = Object.assign({}, obj);
delete dummyObj[key];
const target = Object.assign({}, {...dummyObj});

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)

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

_x000D_
_x000D_
const raw = {_x000D_
  item1: {_x000D_
    key: 'sdfd',_x000D_
    value: 'sdfd'_x000D_
  },_x000D_
  item2: {_x000D_
    key: 'sdfd',_x000D_
    value: 'sdfd'_x000D_
  },_x000D_
  item3: {_x000D_
    key: 'sdfd',_x000D_
    value: 'sdfd'_x000D_
  }_x000D_
};_x000D_
_x000D_
const allowed = ['item1', 'item3', 'lll'];_x000D_
_x000D_
var finalObj = {};_x000D_
allowed.forEach(allowedVal => {_x000D_
  if (raw[allowedVal])_x000D_
    finalObj[allowedVal] = raw[allowedVal]_x000D_
})_x000D_
console.log(finalObj)
_x000D_
_x000D_
_x000D_

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


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
},{})

use PropPick package


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


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;

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).


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

_x000D_
_x000D_
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);
_x000D_
_x000D_
_x000D_


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,
      {}
    );
  }

  sanitize(data, whitelist)

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>
    );
});

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;
}

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.


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

I was playing with "Destructuring" feature :

_x000D_
_x000D_
const raw = {_x000D_
    item1: { key: 'sdfd', value: 'sdfd' },_x000D_
    item2: { key: 'sdfd', value: 'sdfd' },_x000D_
    item3: { key: 'sdfd', value: 'sdfd' }_x000D_
  };_x000D_
var myNewRaw = (({ item1, item3}) => ({ item1, item3 }))(raw);_x000D_
console.log(myNewRaw);
_x000D_
_x000D_
_x000D_


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.


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 –

_x000D_
_x000D_
const oreduce = (f, acc, o) =>_x000D_
  Object_x000D_
    .entries (o)_x000D_
    .reduce_x000D_
      ( (acc, [ k, v ]) => f (acc, v, k, o)_x000D_
      , acc_x000D_
      )_x000D_
_x000D_
const ofilter = (f, o) =>_x000D_
  oreduce_x000D_
    ( (acc, v, k, o)=>_x000D_
        f (v, k, o)_x000D_
          ? Object.assign (acc, { [k]: v })_x000D_
          : acc_x000D_
    , {}_x000D_
    , o_x000D_
    )_x000D_
_x000D_
const data =_x000D_
  { item1: { key: 'a', value: 1 }_x000D_
  , item2: { key: 'b', value: 2 }_x000D_
  , item3: { key: 'c', value: 3 }_x000D_
  }_x000D_
_x000D_
console.log_x000D_
  ( ofilter_x000D_
      ( (v, k) => k !== 'item2'_x000D_
      , data_x000D_
      )_x000D_
      // [ { item1: { key: 'a', value: 1 } }_x000D_
      // , { item3: { key: 'c', value: 3 } }_x000D_
      // ]_x000D_
_x000D_
  , ofilter_x000D_
      ( x => x.value === 3_x000D_
      , data_x000D_
      )_x000D_
      // [ { item3: { key: 'c', value: 3 } } ]_x000D_
  )
_x000D_
_x000D_
_x000D_

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


Piggybacking on ssube's answeranswer.

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.


Simple Way! To do this.

_x000D_
_x000D_
const myData = {_x000D_
  item1: { key: 'sdfd', value:'sdfd' },_x000D_
  item2: { key: 'sdfd', value:'sdfd' },_x000D_
  item3: { key: 'sdfd', value:'sdfd' }_x000D_
};_x000D_
const{item1,item3}=myData_x000D_
const result =({item1,item3})
_x000D_
_x000D_
_x000D_


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


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' }}

Another short way

_x000D_
_x000D_
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
  //}
_x000D_
_x000D_
_x000D_