Filter object properties by key in ES6

JavascriptEcmascript 6Filter

Javascript Problem Overview


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.

Javascript Solutions


Solution 1 - Javascript

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
  3. Array.prototype.includes to make sure they are present
  4. 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.

Solution 2 - Javascript

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

Solution 3 - Javascript

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

Solution 4 - Javascript

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)

Solution 5 - Javascript

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

Solution 6 - Javascript

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

Solution 7 - Javascript

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

Solution 8 - Javascript

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

Solution 9 - Javascript

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

Solution 10 - Javascript

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

Solution 11 - Javascript

This is how I did it, recently:

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

Solution 12 - Javascript

Building on these two answers:

https://stackoverflow.com/a/56081419/13819049<br/> https://stackoverflow.com/a/54976713/13819049

We can do:

const original = { a: 1, b: 2, c: 3 };
const allowed = ['a', 'b'];

const filtered = Object.fromEntries(allowed.map(k => [k, original[k]]));

Which is cleaner and faster:

https://jsbench.me/swkv2cbgkd/1

Solution 13 - Javascript

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

Solution 14 - Javascript

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.

Solution 15 - Javascript

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

Solution 16 - Javascript

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

Solution 17 - Javascript

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

Solution 18 - Javascript

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.

Solution 19 - Javascript

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.

Solution 20 - Javascript

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;

Solution 21 - Javascript

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

Solution 22 - Javascript

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

Solution 23 - Javascript

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

Solution 24 - Javascript

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.

Solution 25 - Javascript

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

Solution 26 - Javascript

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

Solution 27 - Javascript

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

Solution 28 - Javascript

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.

Solution 29 - Javascript

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

Solution 30 - Javascript

use PropPick package


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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Question29erView Question on Stackoverflow
Solution 1 - JavascriptssubeView Answer on Stackoverflow
Solution 2 - JavascriptRyan H.View Answer on Stackoverflow
Solution 3 - JavascriptClemens HelmView Answer on Stackoverflow
Solution 4 - JavascriptGuy SegevView Answer on Stackoverflow
Solution 5 - Javascriptdudi harushView Answer on Stackoverflow
Solution 6 - JavascriptNovyView Answer on Stackoverflow
Solution 7 - JavascriptinabramovaView Answer on Stackoverflow
Solution 8 - JavascriptWiltView Answer on Stackoverflow
Solution 9 - JavascriptMulanView Answer on Stackoverflow
Solution 10 - JavascriptJoey GrisafeView Answer on Stackoverflow
Solution 11 - JavascriptRajat SaxenaView Answer on Stackoverflow
Solution 12 - JavascriptpdcribeiroView Answer on Stackoverflow
Solution 13 - JavascriptItai NoamView Answer on Stackoverflow
Solution 14 - JavascriptEvan PlaiceView Answer on Stackoverflow
Solution 15 - Javascriptghanshyam bendkoliView Answer on Stackoverflow
Solution 16 - JavascriptBouniView Answer on Stackoverflow
Solution 17 - JavascriptKonrad AlbrechtView Answer on Stackoverflow
Solution 18 - Javascriptwiktus239View Answer on Stackoverflow
Solution 19 - Javascriptd4nyllView Answer on Stackoverflow
Solution 20 - JavascriptEsin ÖNERView Answer on Stackoverflow
Solution 21 - JavascriptCCD WhiteView Answer on Stackoverflow
Solution 22 - JavascriptAdam111pView Answer on Stackoverflow
Solution 23 - JavascriptJaysQubeXonView Answer on Stackoverflow
Solution 24 - JavascriptcpcallenView Answer on Stackoverflow
Solution 25 - JavascriptAlirezaView Answer on Stackoverflow
Solution 26 - JavascriptKhaled OsmanView Answer on Stackoverflow
Solution 27 - JavascriptRyan DhungelView Answer on Stackoverflow
Solution 28 - JavascriptSakshamView Answer on Stackoverflow
Solution 29 - JavascriptАннаView Answer on Stackoverflow
Solution 30 - JavascriptRomuloVSView Answer on Stackoverflow