Home > OS >  What am I doing wrong when filtering out data from a multi-level object?
What am I doing wrong when filtering out data from a multi-level object?

Time:04-27

Trying to understand and practice manipulation of passed in data I have created an array of objects:

const pizzaObj = [
  {
    id: 'mon',
    name: 'Monday',
    subMenu: [],
  },
  {
    id: 'tues',
    name: 'Tuesday',
    subMenu: [
      {
        id: 'small',
        name: 'Small',
      },
      {
        id: 'medium',
        name: 'Medium',
      },
      {
        id: 'large',
        name: 'Large',
      },
      {
        id: 'xlarge',
        name: 'X Large',
      },
    ],
  },
  {
    id: 'wed',
    name: 'Wednesday',
    subMenu: [],
  },
]

that I'm trying to filter out medium and large from the subMenu so it will look like:

const pizzaObj = [
  {
    id: 'mon',
    name: 'Monday',
    subMenu: [],
  },
  {
    id: 'tues',
    name: 'Tuesday',
    subMenu: [
      {
        id: 'small',
        name: 'Small',
      },
      {
        id: 'xlarge',
        name: 'X Large',
      },
    ],
  },
  {
    id: 'wed',
    name: 'Wednesday',
    subMenu: [],
  },
]

I can remove if just targeting the subMenu:

const listToDelete = ['medium', 'large']

const pizzaObj = [
      {
        id: 'small',
        name: 'Small',
      },
      {
        id: 'medium',
        name: 'Medium',
      },
      {
        id: 'large',
        name: 'Large',
      },
      {
        id: 'xlarge',
        name: 'X Large',
      },
    ]

const result = pizzaObj.filter( el => (-1 == listToDelete.indexOf(el.id)) )

console.log(result)

But when I try filtering with the object using some the data isn't removed:

const listToDelete = ['medium', 'large']

const pizzaObj = [
  {
    id: 'mon',
    name: 'Monday',
    subMenu: [],
  },
  {
    id: 'tues',
    name: 'Tuesday',
    subMenu: [
      {
        id: 'small',
        name: 'Small',
      },
      {
        id: 'medium',
        name: 'Medium',
      },
      {
        id: 'large',
        name: 'Large',
      },
      {
        id: 'xlarge',
        name: 'X Large',
      },
    ],
  },
  {
    id: 'wed',
    name: 'Wednesday',
    subMenu: [],
  },
]

const result = pizzaObj.filter(m => {
  return Object.keys(m).some(key => {
    return key === 'subMenu'
      ? m[key].filter(item => -1 === listToDelete.indexOf(item.id))
      : m[key]
  })
})

console.log(result)

I've also tried with map:

const pizzaObj = [
  {
    id: 'mon',
    name: 'Monday',
    subMenu: [],
  },
  {
    id: 'tues',
    name: 'Tuesday',
    subMenu: [
      {
        id: 'small',
        name: 'Small',
      },
      {
        id: 'medium',
        name: 'Medium',
      },
      {
        id: 'large',
        name: 'Large',
      },
      {
        id: 'xlarge',
        name: 'X Large',
      },
    ],
  },
  {
    id: 'wed',
    name: 'Wednesday',
    subMenu: [],
  },
]

const testStrip = data => {
  const listToDelete = ['medium', 'large']
  
return data.filter(m => {
  return Object.keys(m).map(key => {
    return key === 'subMenu'
      ? m[key].filter(item => -1 === listToDelete.indexOf(item.id))
      : m[key]
  })
})
}

console.log(testStrip(pizzaObj))

Research:

What am I misunderstanding and how should I be filtering out medium and large?

CodePudding user response:

Since you're dealing with multiple objects in an array, why not use forEach() to loop over them, and reassign subMenu using filter() as you've already done:

const pizzaObj = [{id: 'mon', name: 'Monday', subMenu: [], }, {id: 'tues', name: 'Tuesday', subMenu: [{id: 'small', name: 'Small', }, {id: 'medium', name: 'Medium', }, {id: 'large', name: 'Large', }, {id: 'xlarge', name: 'X Large', }, ], }, {id: 'wed', name: 'Wednesday', subMenu: [], }, ]

const testStrip = data => {
  data.forEach(d => {
    d.subMenu = d.subMenu.filter(p => !['Medium', 'Large'].includes(p.name))
  });
  return data;
}

console.log(testStrip(pizzaObj))


Same idea, but with reduce() which gives some more control if needed:

const pizzaObj = [{id: 'mon', name: 'Monday', subMenu: [], }, {id: 'tues', name: 'Tuesday', subMenu: [{id: 'small', name: 'Small', }, {id: 'medium', name: 'Medium', }, {id: 'large', name: 'Large', }, {id: 'xlarge', name: 'X Large', }, ], }, {id: 'wed', name: 'Wednesday', subMenu: [], }, ]

const testStrip = data => (
    data.reduce((prev, cur) => [
        ...prev,
        { 
            ...cur, 
            subMenu: cur.subMenu = cur.subMenu.filter(p => !['Medium', 'Large'].includes(p.name))
        }
    ], [])
)

console.log(testStrip(pizzaObj))

CodePudding user response:

You can do something like this

const filterData = (data, exclude) => 
  data.map(d => ({
   ...d,
   subMenu: d.subMenu.filter(({id}) => !exclude.includes(id))
  }))



const listToDelete = ['medium', 'large']


const pizzaObj = [
  {
    id: 'mon',
    name: 'Monday',
    subMenu: [],
  },
  {
    id: 'tues',
    name: 'Tuesday',
    subMenu: [
      {
        id: 'small',
        name: 'Small',
      },
      {
        id: 'medium',
        name: 'Medium',
      },
      {
        id: 'large',
        name: 'Large',
      },
      {
        id: 'xlarge',
        name: 'X Large',
      },
    ],
  },
  {
    id: 'wed',
    name: 'Wednesday',
    subMenu: [],
  },
]

console.log(filterData(pizzaObj, listToDelete))

  • Related