0

Let's say I have an object with the structure

data = {
    a : [{values: {key1: 5, key2: "abc"}}, {values: {key1: 3, key2: "abc"}}, {values: {key1: 4, key2: "cde"}}],
    b : [{values: {key1: 3, key2: "ffe"}}, {values: {key1: 11, key2: "gga"}}, {values: {key1: 7, key2: "abc"}}]
}

I want to extract elements where key2 == "abc".

Expected output:

data = {
    a : [{values: {key1: 5, key2: "abc"}}, {values: {key1: 3, key2: "abc"}}],
    b : [{values: {key1: 7, key2: "abc"}}]
}

I've tried to follow similar examples but failed to implement what I wanted.

0

5 Answers 5

8

Use Object.entries() to extract all the key / value pairs of data as an array, map over each pair and then filter on each value to extract the ones you want.

You can then join it back up using Object.fromEntries()

const data = {
    a : [{values: {key1: 5, key2: "abc"}}, {values: {key1: 3, key2: "abc"}}, {values: {key1: 4, key2: "cde"}}],
    b : [{values: {key1: 3, key2: "ffe"}}, {values: {key1: 11, key2: "gga"}}, {values: {key1: 7, key2: "abc"}}]
}

const findKey = 'key2'
const findValue = 'abc'

const newData = Object.fromEntries(Object.entries(data).map(([ key, val ]) =>
  [ key, val.filter(({ values }) => values?.[findKey] === findValue) ]))
  
console.log(newData)


In case you haven't seen Optional Chaining yet, this...

values?.[findKey] === findValue

is equivalent to

!!values && values[findKey] === findValue
Sign up to request clarification or add additional context in comments.

7 Comments

My brain hurts trying to follow all the destructuring going on there.
While this works there is so much destructuring here that you might loose the flow
@ManosKounelakis there are only two destructures here, one array ([ key, val ]) and one object ({ value }). Not sure what you consider too much?
do you actually need the optional chaining? i thought if you try to access a property at the first layer that is not there it returns undefined?
@Ifaruki it's there in case any of the array entries doesn't have a values property. If they did, values would be undefined and values[findKey] would throw an error
|
4

Simple for of loop that iterates over keys and filters the arrays and reassigns properties directly.
Mutates data directly.

Uses filter and destructures key2 to filter on it.

const data = {
    a : [{values: {key1: 5, key2: "abc"}}, {values: {key1: 3, key2: "abc"}}, {values: {key1: 4, key2: "cde"}}],
    b : [{values: {key1: 3, key2: "ffe"}}, {values: {key1: 11, key2: "gga"}}, {values: {key1: 7, key2: "abc"}}]
}

for(const k of Object.keys(data))
  data[k] = data[k].filter(({values: {key2}})=>key2==='abc')
  
console.log(data)

Added check of .length to prune keys with empty arrays,
and set default value for key2 so values property is optional:

const data = {
    a : [{values: {key1: 5, key2: "abc"}}, {values: {key1: 3, key2: "abc"}}, {values: {key1: 4, key2: "cde"}}],
    b : [{values: {key1: 3, key2: "ffe"}}, {values: {key1: 11, key2: "gga"}}, {values: {key1: 7, key2: "abc"}}]
}

for(const k of Object.keys(data))
  (data[k] = data[k].filter(({values:{key2}={}})=>key2==='abc'))
    .length || delete data[k]
  
console.log(data)

Comments

1
data = {
    a : [{values: {key1: 5, key2: "abc"}}, {values: {key1: 3, key2: "abc"}}, {values: {key1: 4, key2: "cde"}}],
    b : [{values: {key1: 3, key2: "ffe"}}, {values: {key1: 11, key2: "gga"}}, {values: {key1: 7, key2: "abc"}}]
}

var resp = {}
for (var key in data){
    var local = [];
    data[key].forEach(element => {
        if(element['values']['key2'] == 'abc'){
            local.push(element);
        }
    })
    resp[key] = local;
}
console.log(resp);

Response

a : [{values: {key1: 5, key2: "abc"}}, {values: {key1: 3, key2: "abc"}}],
b : [{values: {key1: 7, key2: "abc"}}]

Comments

1

You can reduce the properties of the object to the ones that pass a filter

const data = {
    a : [{values: {key1: 5, key2: "abc"}}, {values: {key1: 3, key2: "abc"}}, {values: {key1: 4, key2: "cde"}}],
    b : [{values: {key1: 3, key2: "ffe"}}, {values: {key1: 11, key2: "gga"}}, {values: {key1: 7, key2: "abc"}}]
};

const results = Object.getOwnPropertyNames(data).reduce((results, key) => {
  const filtered = data[key].filter(item => item.values.key2 === 'abc');
  if (filtered && filtered.length) {
    results[key] = filtered;
  }
  return results;
}, {});

console.log(results);

1 Comment

Might need to clarify with OP if they want empty results omitted but that's a nice addition
0

As you need to iterate over your objects attributes I suggest you to extract them with Object.keys(object) which you can find here:

https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/keys

I suggest you to iterate like this:

Object.keys(data).forEach(attribute => {
        data[attribute] = data[attribute].filter(value => value.values.key2 === 'abc');
})

Good luck.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.